diff -u --recursive --new-file v2.3.9/linux/CREDITS linux/CREDITS
--- v2.3.9/linux/CREDITS	Wed Jun 30 13:38:18 1999
+++ linux/CREDITS	Tue Jul  6 10:19:57 1999
@@ -163,7 +163,7 @@
 D: Various bugfixes and changes to sound drivers
 S: USA 
 
-M: Krzysztof G. Baranowski
+N: Krzysztof G. Baranowski
 E: kgb@manjak.knm.org.pl
 P: 1024/FA6F16D1 96 D1 1A CF 5F CA 69 EC  F9 4F 36 1F 6D 60 7B DA
 D: Maintainer of the System V file system.
@@ -174,6 +174,17 @@
 S: 62-300 Wrzesnia
 S: Poland
 
+N: Carlos Henrique Bauer
+E: chbauer@acm.org
+E: bauer@atlas.unisinos.tche.br
+D: A test for detection of EPP-1.7 and ECP/EPP parports.
+D: Some new sysctl entries for the parport driver.
+S: Universidade do Vale do Rio dos Sinos - UNISINOS
+S: DSI/IDASI
+S: Av. Unisinos, 950
+S: 93022000 Sao Leopoldo RS
+S: Brazil
+
 N: Peter Bauer
 E: 100136.3530@compuserve.com
 D: Driver for depca-ethernet-board
@@ -869,13 +880,11 @@
 S: 65760 Eschborn
 S: Germany
 
-N: Kenji Tsutomu Hollis
-E: khollis@bitgate.com
-W: http://www.nurk.org/
+N: Kenji Hollis
+E: kenji@bitgate.com
+W: http://www.bitgate.com/
 D: Berkshire PC Watchdog Driver
-S: Post Office Box 15
-S: Grants Pass, Oregon 97526
-S: USA
+D: Small/Industrial Driver Project
 
 N: Nick Holloway
 E: Nick.Holloway@alfie.demon.co.uk
@@ -1660,6 +1669,15 @@
 S: 4390 Albany Drive #41A
 S: San Jose, California 95129
 S: USA
+
+N: Augusto Cesar Radtke
+E: bishop@sekure.org
+W: http://bishop.sekure.org
+D: {copy,get,put}_user calls updates
+D: Miscellaneous hacks
+S: R. Otto Marquardt, 226 - Garcia
+S: 89020-350 Blumenau - Santa Catarina
+S: Brazil
 
 N: Eric S. Raymond
 E: esr@thyrsus.com
diff -u --recursive --new-file v2.3.9/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.9/linux/Documentation/Changes	Fri May  7 09:31:25 1999
+++ linux/Documentation/Changes	Thu Jul  1 10:54:31 1999
@@ -191,12 +191,6 @@
 users should especially try to use the 2.9.1.0.x releases, as they
 resolve known issues with glibc2 and binutils-2.8.x releases.
 
-   libbfd, libiberty, and /usr/include/bfd.h, which are part of recent
-binutils packages, are also required to compile ksymoops.  Depending
-upon your distribution, this may require you to install both binutils
-and binutils-development packages (Debian puts bfd.h in binutils-dev,
-for example).
-
 Gnu C
 =====
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.9/linux/Documentation/Configure.help	Wed Jun 30 13:38:18 1999
+++ linux/Documentation/Configure.help	Mon Jul  5 20:37:25 1999
@@ -530,7 +530,7 @@
   People with SCSI-only systems should say N here; if unsure say Y.
 
 Generic PCI bus-master DMA support
-CONFIG_BLK_DEV_IDEDMA
+CONFIG_BLK_DEV_IDEDMA_PCI
   If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
   is capable of bus-master DMA operation (most Pentium PCI systems),
   you will want to say Y here to reduce CPU overhead. You can then use
@@ -546,6 +546,26 @@
 
   It is safe to say Y to this question.
 
+Good-Bad DMA Model-Firmware (EXPERIMENTAL)
+IDEDMA_NEW_DRIVE_LISTINGS
+  This test compares both the model and firmware revision for buggy drives
+  that claim to (U)DMA capable.  This is a blanket on/off test with no speed
+  limit options.  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
+  whereas, many versions of EGCS have a problem and miscompile.
+
+  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
@@ -562,13 +582,16 @@
   improve the usability of some boot managers such as LILO when
   booting from a drive on an off-board controller.
 
+  Requires that all onboard ide controllers be disabled or calling
+  "pci=reverse" to invert the device scan order.
+
   Note that, if you say Y here, the order of the hd* devices will be
   rearranged which may require modification of fstab and other files.
 
   If in doubt, say N.
 
 Use DMA by default when available
-CONFIG_IDEDMA_AUTO
+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,
@@ -664,7 +687,7 @@
   This driver adds detection and support for the CY82C693 chipset
   used on Digital's PC-Alpha 164SX boards.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/cy82c693.c
 
@@ -679,7 +702,7 @@
   (while running a "cat") provided you enabled "proc" support and
   set DISPLAY_APOLLO_TIMINGS in via82c586.c
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   If unsure, say N.
 
@@ -693,14 +716,15 @@
   onboard chipsets.  It also tests for Simplex mode and enables
   normal dual channel support.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/alim15x3.c
 
   If unsure, say N.
 
-PROMISE PDC20246 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC20246
+PROMISE PDC20246/PDC20262 support
+CONFIG_BLK_DEV_PDC202XX
+  Promise Ultra33 or PDC20246.
   This driver adds up to 4 more eide devices sharing a single interrupt.
   This add-on card is a bootable PCI UDMA controller.
   Since multiple cards can be installed and there are BIOS ROM problems
@@ -708,38 +732,49 @@
   do not match.  Should you be unable to make new BIOS chips with a burner,
   the driver attempts to dynamic tuning of the chipset at boot-time
   for max-speed.  Ultra33 BIOS 1.25 or new required for more than one card.
+  This card may require "PDC202XX Special UDMA Feature (EXPERIMENTAL)".
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
-
-  Please read the comments at the top of drivers/block/pdc202xx.c
-
-  If unsure, say N.
-
-PROMISE PDC20262 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC20262
+  Promise Ultra66 or PDC20262.
   This driver adds up to 4 more eide devices sharing a single interrupt.
   This add-on card is a bootable PCI UDMA ATA-66 controller.
   The driver attempts to dynamic tuning of the chipset at boot-time
   for max-speed.  Note tested limits are UDMA-2.
   Ultra66 BIOS 1.11 or newer required.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/pdc202xx.c
 
   If unsure, say N.
 
+Special UDMA Feature (EXPERIMENTAL)
+PDC202XX_FORCE_BURST_BIT
+  For PDC20246 and PDC20262 Ultra DMA chipsets.
+  Designed originally for PDC20246/Ultra33 that has BIOS setup failures
+  when using 3 or more cards.
+
+  Please read the comments at the top of drivers/block/pdc202xx.c
+
+  If unsure, say N.
+
+Special Mode Feature (DANGEROUS)
+PDC202XX_FORCE_MASTER_MODE
+  For PDC20246 and PDC20262 Ultra DMA chipsets.
+  This is reserved for possible Hardware RAID 0,1 for the FastTrak Series.
+
+  Say N. 
+
 AEC6210 chipset support
 CONFIG_BLK_DEV_AEC6210
   This driver adds up to 4 more eide devices sharing a single interrupt.
   This add-on card is a bootable PCI UDMA controller.  In order to get this
   card to initialize correctly in some cases, you should include this driver.
 
-  This prefers CONFIG_IDEDMA_AUTO to be enabled, regardless.
+  This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless.
 
   Please read the comments at the top of drivers/block/aec6210.c
 
-Intel PIIXn chipsets support (EXPERIMENTAL)
+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
@@ -750,15 +785,31 @@
 
   If unsure, say N.
 
-HPT343 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_HPT343
+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.
+
+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
-  PCI UDMA controller. 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.
+  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/hpt343.c
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+HPT34X DMA support (DANGEROUS)
+CONFIG_BLK_DEV_HPT34X_DMA
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/hpt343.c
 
@@ -821,17 +872,17 @@
   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
-
- Use DMA by default
- CONFIG_PMAC_IDEDMA_AUTO
-   No help for CONFIG_PMAC_IDEDMA_AUTO
+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
+
+Use DMA by default
+CONFIG_IDEDMA_PMAC_AUTO
+  No help for CONFIG_IDEDMA_PMAC_AUTO
 
 Macintosh Quadra/Powerbook IDE interface support
 CONFIG_BLK_DEV_MAC_IDE
@@ -843,9 +894,21 @@
   (hard disks, CD-ROM drives, etc.) that are connected to the builtin
   IDE interface.
 
- RapIDE interface support
- CONFIG_BLK_DEV_IDE_RAPIDE
-   No help for CONFIG_BLK_DEV_IDE_RAPIDE
+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
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
@@ -1611,6 +1674,45 @@
 CONFIG_FB_SGIVW
   SGI Visual Workstation support for framebuffer graphics.
 
+I2O support
+CONFIG_I2O
+  The Intelligent Input/Output (I2O) architecture allows
+  hardware drivers to be split into two parts: an operating system
+  specific module called the OSM and an hardware specific module
+  called the HDM. The OSM can talk to a whole range of HDM's, and
+  ideally the HDM's are not OS dependent. This allows for the same
+  driver to be used under different operating systems if the relevant
+  OSM is in place. If you say Y here, you will get a choice of OSM's
+  with the following questions.
+
+  This support is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
+  If unsure, say N.
+
+I2O PCI support
+CONFIG_I2O_PCI
+  Build in support for PCI bus I2O interface adapters. Currently this
+  is the only variety supported.
+
+I2O Block OSM
+CONFIG_I2O_BLOCK
+  Include support for the I2O Block OSM. The Block OSM presents disk and
+  other structured block devices to the operating system.
+
+I2O LAN OSM
+CONFIG_I2O_LAN
+  Include support for the LAN OSM. You will also need to include support
+  for token ring or fddi if you wish to use token ring or FDDI I2O cards
+  with this driver.
+
+I2O SCSI OSM
+CONFIG_I2O_SCSI
+  Allow direct scsi access to scsi devices on a SCSI or FibreChannel I2O 
+  controller. You can use both the SCSI and Block OSM together if you wish.
+
 System V IPC
 CONFIG_SYSVIPC
   Inter Process Communication is a suite of library functions and
@@ -1977,6 +2079,11 @@
   You will get a boot time penguin logo at no additional cost. Please
   read Documentation/fb/vesafb.txt. If unsure, say Y.
 
+VGA 16-color graphics console
+CONFIG_FB_VGA16
+  This is the frame buffer device driver for VGA 16 color graphic
+  cards. Say Y if you have such a card.
+
 Backward compatibility mode for Xpmac
 CONFIG_FB_COMPAT_XPMAC
   If you use the Xpmac X server (common with mklinux), you'll need to
@@ -2218,12 +2325,12 @@
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called parport.o. If you have more than one
   parallel port and want to specify which port and IRQ to be used by
-  this driver at module load time, read
-  Documentation/networking/net-modules.txt.
+  this driver at module load time, take a look at
+  Documentation/networking/parport.txt.
 
   If unsure, say Y.
 
-PC-style hardware 
+PC-style hardware
 CONFIG_PARPORT_PC
   You should say Y here if you have a PC-style parallel port. All IBM
   PC compatible computers and some Alphas have PC-style parallel
@@ -2236,28 +2343,36 @@
   
   If unsure, say Y.
 
+Use FIFO/DMA if available
+CONFIG_PARPORT_PC_FIFO
+  Many parallel port chipsets provide hardware that can speed up
+  printing. Say Y here if you want to take advantage of that.
+
+  As well as actually having a FIFO, or DMA capability, the kernel
+  will need to know which IRQ the parallel port has. By default,
+  parallel port interrupts will not be used, and so neither will the
+  FIFO. See Documentation/parport.txt to find out how to specify
+  which IRQ/DMA to use.
+
 Support foreign hardware
 CONFIG_PARPORT_OTHER
   Say Y here if you want to be able to load driver modules to support
   other non-standard types of parallel ports. This causes a
   performance loss, so most people say N.
 
-Sun Ultra/AX-style hardware 
+Sun Ultra/AX-style hardware
 CONFIG_PARPORT_AX
   Say Y here if you need support for the parallel port hardware on Sun
   Ultra/AX machines. This code is also available as a module (say M),
   called parport_ax.o. If in doubt, saying N is the safe plan.
 
-Plug and Play support
-CONFIG_PNP
-  Plug and Play support allows the kernel to automatically configure
-  some peripheral devices. Say Y to enable PnP.
-
-Auto-probe for parallel devices
-CONFIG_PNP_PARPORT
-  Some IEEE-1284 conforming parallel-port devices can identify
-  themselves when requested. Say Y to enable this feature, or M to
-  compile it as a module (parport_probe.o). If in doubt, say N.
+IEEE1284 transfer modes
+CONFIG_PARPORT_1284
+  If you have a printer that supports status readback or device ID, or
+  want to use a device that uses enhanced parallel port transfer modes
+  such as EPP and ECP, say Y here to enable advanced IEEE 1284
+  transfer modes. Also say Y if you want device ID information to
+  appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
 
 Enable loadable module support
 CONFIG_MODULES
@@ -5160,6 +5275,17 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+Aironet Arlan 655 & IC2200 DS support
+CONFIG_ARLAN
+  Aironet makes Arlan. www.aironet.com. Uses www.Telxon.com chip, which is
+  used on several similar cards. Driver is tested on 655 and IC2200 series. 
+  Look for http://www.ylenurme.ee/~elmer/655/ for latest information. 
+  Driver is build as two modules, arlan and arlan-proc. The later is /proc
+  interface and not needed most of time.
+  On some computers the card ends up in non-valid state after some time.
+  Use a ping-reset script to clear it.
+   
+
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
   This is a driver for a pseudo device (typically called /dev/lapb0)
@@ -5286,6 +5412,15 @@
   module, say M here and read Documentation/modules.txt. If you don't
   know what to use this for, you don't need it.
 
+Sealevel Systems 4021 support
+CONFIG_SEALEVEL_4021
+  This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
+  
+  This driver can only be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to do that, say M here. The module will be called
+  sealevel.o.
+
 Frame Relay (DLCI) support
 CONFIG_DLCI
   This is support for the frame relay protocol; frame relay is a fast
@@ -5692,6 +5827,40 @@
   you say N, the PPP support will not be included in the driver (saves
   about 16 KB of kernel memory).
 
+Cyclom 2X(tm) multiprotocol cards
+CONFIG_CYCLADES_SYNC
+  Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and
+  http://www.cyclades.com.br; to browse the WWW, you need to have
+  access to a machine on the Internet that has a program like lynx or
+  netscape) is an intelligent multiprotocol WAN adapter with data
+  transfer rates up to 512 Kbps). These cards support the X.25 and SNA
+  related protocols. If you have one or more of these cards, say Y to
+  this option. The next questions will ask you about the protocols you
+  want the driver to support (for now only X.25 is supported).
+
+  While no documentation is available at this time please grab the
+  wanconfig tarball in http://www.conectiva.com.br/~acme/cycsyn-devel
+  (with minor changes to make it compile with the current wanrouter
+  include files; efforts are being made to use the original package
+  available at ftp://ftp.sangoma.com).
+
+  Feel free to contact me or the cycsyn-devel mailing list at
+  acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
+  aditional details, I hope to have documentation available as soon
+  as possible.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cyclomx.o. For general information about
+  modules read Documentation/modules.txt.
+
+Cyclom 2X X.25 support
+CONFIG_CYCLOMX_X25
+  Say Y to this option if you are planning to connect a Cyclom 2X card
+  to an X.25 network. 
+  If you say N, the X.25 support will not be included in the driver
+  (saves about 11 KB of kernel memory).
+
 Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
   Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
@@ -5905,7 +6074,7 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called yellowfin.o.
 
-Alteon AceNIC / 3Com 3C985 Gigabit Ethernet support.
+Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
   Ethernet adapter. The driver allows for using the Jumbo Frame
@@ -6663,6 +6832,25 @@
   The module will be called ibmtr.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+IBM Olympic chipset PCI adapter support
+CONFIG_IBMOL
+  This is support for all non-Lanstreamer IBM PCI Token Ring Cards. 
+  Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II
+  Wake On Lan, and PCI 100/16/4 adapters.
+
+  If you have such an adapter, say Y and read the Token-Ring mini-HOWTO,
+  available via FTP (user:anonymous) from
+  ftp://metalab.unc/edu/pub/Linux/docs/HOWTO.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will will be called olympic.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  Also read the linux/Documentation/networking/olympic.txt or check the 
+  Linux Token Ring Project site for the latest information at
+  http://www.linuxtr.net
+
 SysKonnect adapter support
 CONFIG_SKTR
   This is support for all SysKonnect Token Ring cards, specifically
@@ -8316,6 +8504,16 @@
 
   If you haven't heard about it, it's safe to say N.
 
+Cyclades-Z interrupt mode operation (EXPERIMENTAL)
+CONFIG_CYZ_INTR
+  The Cyclades-Z family of multiport cards allows 2 (two) driver
+  op modes: polling and interrupt. In polling mode, the driver will
+  check the status of the Cyclades-Z ports every certain amount of
+  time (which is called polling cycle and is configurable). In
+  interrupt mode, it will use an interrupt line (IRQ) in order to check
+  the status of the Cyclades-Z ports. The default op mode is polling.
+  If unsure, say N.
+
 Stallion multiport serial support 
 CONFIG_STALDRV
   Stallion cards give you many serial ports. You would need something
@@ -8440,7 +8638,8 @@
   corresponding drivers into the kernel. If you want to compile this
   driver as a module however ( = 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 lp.o. 
+  read Documentation/modules.txt and Documentation/parport.txt. The
+  module will be called lp.o. 
 
   If you have several parallel ports, you can specify which ports to
   use with the "lp" kernel command line option. (Try "man bootparam"
@@ -8454,11 +8653,18 @@
   If you have more than 3 printers, you need to increase the LP_NO
   variable in lp.c.
 
-Support IEEE1284 status readback
-CONFIG_PRINTER_READBACK
-  If your printer conforms to IEEE 1284, it may be able to provide a
-  status indication when you read from it (for example, with `cat
-  /dev/lp1'). To use this feature, say Y here.
+Support for console on line printer
+CONFIG_LP_CONSOLE
+  If you want kernel messages to be printed out as they occur, you
+  can have a console on the printer. This option adds support for
+  doing that; to actually get it to happen you need to pass the
+  option "console=lp" to the kernel at boot time.
+
+  Note that kernel messages can get lost if the printer is out of
+  paper (or off, or unplugged, or too busy..), but this behaviour
+  can be changed. See drivers/char/lp.c (do this at your own risk).
+
+  If unsure, say N.
 
 Mouse Support (not serial mice)
 CONFIG_MOUSE
@@ -9397,7 +9603,7 @@
   after the PnP configuration is finished. To do this, say M here and
   read Documentation/modules.txt as well as
   Documentation/sound/README.modules; the module will be called
-  sound.o.
+  soundcore.o.
 
   I'm told that even without a sound card, you can make your computer
   say more than an occasional beep, by programming the PC speaker.
@@ -10943,6 +11149,11 @@
   Choose Y here if you have this FM radio card, and then fill in the 
   port address below.
 
+  If you have GemTeks combined (PnP) sound- and radio card you must use
+  this driver as a module and setup the card with isapnptools. You must
+  also pass the module a suitable io parameter, 0x248 has been reported
+  to be used by these cards.
+
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
   this API and pointers to "v4l" programs may be found on the WWW at
@@ -11119,6 +11330,40 @@
   Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
   0x34c, if you haven't changed the jumper setting on the card.
 
+PlanB Video-In for PowerMacs
+CONFIG_VIDEO_PLANB
+  PlanB is the V4L driver for the PowerMac 7x00/8x00 series video
+  input hardware. If you want to experiment with this, say Y.
+  Otherwise, or if you don't understand a word, say N.
+  See http://www.cpu.lu/~mlan/planb.html for more info.
+
+  Saying M will compile this driver as a module (planb.o).
+
+TerraTec ActiveRadio
+CONFIG_RADIO_TERRATEC
+  Choose Y here if you have this FM radio card, and then fill in the
+  port address below. (TODO)
+
+  Note: This driver is in its early stages. Right now volume and frequency
+  control and muting works at least for me, but unfortunately i have not
+  found anybody who wants to use this card with linux. So if it is this
+  what YOU are trying to do right now, PLEASE DROP ME A NOTE!!
+  Rolf Offermanns (rolf@offermanns.de)
+  
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API. Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape.
+
+
+  If you want to compile this 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 radio-terratec.o.
+  
+
 BT848 Video For Linux
 CONFIG_VIDEO_BT848
   Support for BT848 based frame grabber/overlay boards. This includes
@@ -11165,6 +11410,14 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+Compaq SMART2 support
+CONFIG_BLK_CPQ_DA
+   This is the driver for Compaq Smart Array controllers.  
+   Everyone using these boards should say Y here.  
+   See "linux/Documentation/cpqarray.txt" for the current list of 
+   boards supported by this driver, and for further information 
+   on the use of this driver. 
+ 
 #
 # ARM options
 #
@@ -11463,6 +11716,21 @@
 
   If unsure, say Y.
 
+IrPORT IrDA Device Driver
+CONFIG_IRPORT_SIR
+  Say Y here if you want to build support for the IrPORT IrDA device
+  driver. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt. IrPORT can be used instead of
+  IrTTY and sometimes this can be better. One example is if your
+  IrDA port does not have echo-canceling, which will work OK with
+  IrPORT since this driver is working in half-duplex mode only. You
+  don't need to use irattach with IrPORT, but you just insert it 
+  the same way as FIR drivers (insmod irport io=0x3e8 irq=11).
+  Notice that IrPORT is a SIR device driver which means that speed
+  is limited to 115200 bps.
+
+  If unsure, say Y.
+
 Winbond W83977AF IrDA Device Driver
 CONFIG_WINBOND_FIR
   Say Y here if you want to build IrDA support for the Winbond
@@ -11486,6 +11754,13 @@
   read Documentation/modules.txt. This chipset is used by the Toshiba
   Tecra laptops.
 
+Toshiba Type-O IR Port Device Driver
+CONFIG_TOSHIBA_FIR
+  Say Y here if you want to build support for the Toshiba Type-O IR
+  chipset. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt. This chipset is used by the Toshiba
+  Libretto 100CT, and many more laptops.
+
 ESI JetEye PC Dongle
 CONFIG_ESI_DONGLE
   Say Y here if you want to build support for the Extended Systems
@@ -11523,6 +11798,15 @@
   by IrTTY. To activate support for Greenwich dongles you will have to
   insert "irattach -d girbil" in the /etc/irda/drivers script.
 
+Parallax Litelink dongle
+CONFIG_LITELINK_DONGLE
+  Say Y here if you want to build support for the Parallax Litelink
+  dongle. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The Parallax dongle attaches to the
+  normal 9-pin serial port connector, and can currently only be used
+  by IrTTY. To activate support for Parallax dongles you will have to
+  insert "irattach -d litelink" in the /etc/irda/drivers script.
+
 VME (Motorola and BVM) support
 CONFIG_VME
   Say Y here if you want to build a kernel for a 680x0 based VME
@@ -11658,6 +11942,16 @@
 CONFIG_USB_ACM
   This driver allows for devices which support the Abstract Control Model,
   including many USB-based modems, ISDN adapters, and network adapters.
+
+Support for user-space parallel port device drivers
+CONFIG_PPDEV
+  Saying Y to this adds support for /dev/parport device nodes.
+  NB. You have to make them before you can use them:
+    mknod /dev/parport00 c 99 0
+    mknod /dev/parport01 c 99 1
+    mknod /dev/parport10 c 99 16
+    mknod /dev/parport11 c 99 17
+    etc..
 
 #
 # A couple of things I keep forgetting:
diff -u --recursive --new-file v2.3.9/linux/Documentation/SMP.txt linux/Documentation/SMP.txt
--- v2.3.9/linux/Documentation/SMP.txt	Wed Jun 24 14:30:07 1998
+++ linux/Documentation/SMP.txt	Thu Jul  1 10:45:57 1999
@@ -1,7 +1,7 @@
 SMP on x86/Linux is now an official feature and is not experimental.
 Experimental SMP support for other architectures is underway.
 
-Please view linux/Documentation/smp for more information about enabling SMP.
+Please view linux/Documentation/smp.txt for more information about enabling SMP.
 
 SMP support for Linux with up to 16 processors using the Intel MP
 specification. 
diff -u --recursive --new-file v2.3.9/linux/Documentation/cpqarray.txt linux/Documentation/cpqarray.txt
--- v2.3.9/linux/Documentation/cpqarray.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/cpqarray.txt	Mon Jul  5 19:52:13 1999
@@ -0,0 +1,107 @@
+This driver is for Compaq's SMART2 Intellegent Disk Array Controllers.
+
+WARNING:
+--------
+
+This driver comes with NO WARRANTY.  It is not officially supported by
+Compaq.  Do not call technical support.  Use at your own risk.
+
+Supported Cards:
+----------------
+
+This driver is known to work with the following cards:
+
+	* SMART (EISA)
+	* SMART-2/E (EISA)
+	* SMART-2/P
+	* SMART-2DH
+	* SMART-2SL
+	* SMART-221
+	* SMART-3100ES
+	* SMART-3200
+	* Integrated Smart Array Controller
+	* SA 4200
+	* SA 4250ES
+
+It should also work with some really old Disk array adapters, but I am
+unable to test against these cards:
+
+	* IDA
+	* IDA-2
+	* IAES
+
+Installing:
+-----------
+
+You need to build a new kernel to use this device, even if you want to
+use a loadable module.  
+
+Apply the patch to a 2.2.x kernel:
+
+# cd linux
+# patch -p1 <smart2.patch
+
+Then build a new kernel and turn on Compaq SMART2 Disk Array support.
+Create device nodes for the diskarray device:
+
+# mkdev.ida [ctlrs]
+
+Where ctlrs is the number of controllers you have (defaults to 1 if not
+specified).
+
+EISA Controllers:
+-----------------
+
+If you want to use an EISA controller you'll have to supply some
+insmod/lilo paramaters.  If the driver is compiled into the kernel, must
+give it the controller's IO port address at boot time (it is no longer
+necessary to specifiy the IRQ).  For example, if you had two SMART-2/E
+controllers, in EISA slots 1 and 2 you'd give it a boot argument like
+this:
+
+	smart2=0x1000,0x2000
+
+If you were loading the driver as a module, you'd give load it like this:
+
+	insmod cpqarray.o eisa=0x1000,0x2000
+
+You can use EISA and PCI adapters at the same time.
+
+Booting:
+--------
+
+You'll need to use a modified lilo if you want to boot from a disk array.
+Its simply a version of lilo with some code added to tell it how to
+understand Compaq diskarray devices.
+
+Device Naming:
+--------------
+
+You need some entries in /dev for the ida device.  The mkdev.ida script
+can make device nodes for you automatically.  Currently the device setup
+is as follows:
+
+Major numbers:
+	72	ida0
+	73	ida1
+	74	ida2
+	etc...
+
+Minor numbers:
+        b7 b6 b5 b4 b3 b2 b1 b0
+        |----+----| |----+----|
+             |           |
+             |           +-------- Partition ID (0=wholedev, 1-15 partition)
+             |
+             +-------------------- Logical Volume number
+
+The suggested device naming scheme is:
+/dev/ida/c0d0		Controller 0, disk 0, whole device
+/dev/ida/c0d0p1		Controller 0, disk 0, partition 1
+/dev/ida/c0d0p2		Controller 0, disk 0, partition 2
+/dev/ida/c0d0p3		Controller 0, disk 0, partition 3
+
+/dev/ida/c1d1		Controller 1, disk 1, whole device
+/dev/ida/c1d1p1		Controller 1, disk 1, partition 1
+/dev/ida/c1d1p2		Controller 1, disk 1, partition 2
+/dev/ida/c1d1p3		Controller 1, disk 1, partition 3
diff -u --recursive --new-file v2.3.9/linux/Documentation/fb/tgafb.txt linux/Documentation/fb/tgafb.txt
--- v2.3.9/linux/Documentation/fb/tgafb.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/fb/tgafb.txt	Thu Jul  1 10:57:36 1999
@@ -0,0 +1,51 @@
+[Also cloned from vesafb.txt, thanks to Gerd]
+
+What is tgafb?
+===============
+
+This is a driver for DECChip 21030 based graphics framebuffers, a.k.a. TGA
+cards, specifically the following models
+
+ZLxP-E1 (8bpp, 4 MB VRAM)
+ZLxP-E2 (32bpp, 8 MB VRAM)
+ZLxP-E3 (32bpp, 16 MB VRAM, Zbuffer)
+
+This version, tgafb-1.12, is almost a complete rewrite of the code written
+by Geert Uytterhoeven, which was based on the original TGA console code
+written by Jay Estabrook.
+
+Major new features:
+
+ * Support for multiple resolutions, including setting the resolution at
+   boot time, allowing the use of a fixed-frequency monitor.
+ * Complete code rewrite to follow Geert's skeletonfb spec which will allow
+   future implementation of hardware acceleration and other features.
+
+
+Configuration
+=============
+
+You can pass kernel command line options to tgafb with
+`video=tga:option1,option2:value2,option3' (multiple options should be
+separated by comma, values are separated from options by `:').
+Accepted options:
+
+font:X    - default font to use. All fonts are supported, including the
+            SUN12x22 font which is very nice at high resolutions.
+mode:X    - default video mode. See drivers/video/tgafb.c for a list.
+            
+X11
+===
+
+XF68_FBDev should work just fine, but I haven't tested it.  Running
+the XF86_TGA server (reasonably recent versions of which support all TGA
+cards) works fine for me.
+
+One minor problem with XF86_TGA is when running tgafb in resolutions higher
+than 640x480, on switching VCs from tgafb to X, the entire screen is not
+re-drawn and must be manually refreshed. This is an X server problem, not a
+tgafb problem.
+
+Enjoy!
+
+Martin Lucina <mato@kotelna.sk>
diff -u --recursive --new-file v2.3.9/linux/Documentation/java.txt linux/Documentation/java.txt
--- v2.3.9/linux/Documentation/java.txt	Tue Apr 28 14:22:04 1998
+++ linux/Documentation/java.txt	Thu Jul  1 10:47:08 1999
@@ -21,7 +21,7 @@
 2) You have to compile BINFMT_MISC either as a module or into
    the kernel (CONFIG_BINFMT_MISC) and set it up properly.
    If you choose to compile it as a module, you will have
-   to insert it manually with modprobe/insmod, as kerneld
+   to insert it manually with modprobe/insmod, as kmod
    can not easy be supported with binfmt_misc. 
    Read the file 'binfmt_misc.txt' in this directory to know
    more about the configuration process.
@@ -29,14 +29,15 @@
 3) Add the following configuration items to binfmt_misc
    (you should really have read binfmt_misc.txt now):
    support for Java applications:
-     ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:'
+     ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:'
    support for Java Applets:
-     ':Applet:E::html::/usr/local/java/bin/appletviewer:'
+     ':Applet:E::html::/usr/bin/appletviewer:'
    or the following, if you want to be more selective:
-     ':Applet:M::<!--applet::/usr/local/java/bin/appletviewer:'
+     ':Applet:M::<!--applet::/usr/bin/appletviewer:'
 
-   Of cause you have to fix the path names, if you installed the JDK
-   at another place than /usr/local/java.
+   Of cause you have to fix the path names. Given path/file names in this
+   document match the Debian 2.1 system. (i.e. jdk installed in /usr,
+   custom wrappers from this document in /usr/local)
 
    Note, that for the more selective applet support you have to modify
    existing html-files to contain <!--applet--> in the first line
@@ -45,42 +46,300 @@
    For the compiled Java programs you need a wrapper script like the
    following (this is because Java is broken in case of the filename
    handling), again fix the path names, both in the script and in the
-   above given configuration string:
+   above given configuration string.
+
+   You, too, need the little program after the script. Compile like
+   gcc -O2 -o javaclassname javaclassname.c
+   and stick it to /usr/local/bin.
+
+   Both the javawrapper shellscript and the javaclassname program
+   were supplied by Colin J. Watson <cjw44@cam.ac.uk>.
 
 ====================== Cut here ===================
 #!/bin/bash
-# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java
-CLASS=$1
+# /usr/local/bin/javawrapper - the wrapper for binfmt_misc/java
 
-# if classname is a link, we follow it (this could be done easier - how?)
-if [ -L "$1" ] ; then
-        CLASS=`ls --color=no -l $1 | tr -s '\t ' '  ' | cut -d ' ' -f 11`
+if [ -z "$1" ]; then
+	exec 1>&2
+	echo Usage: $0 class-file
+	exit 1
 fi
-CLASSN=`basename $CLASS .class`
-CLASSP=`dirname $CLASS`
 
-FOO=$PATH
-PATH=$CLASSPATH
-if [ -z "`type -p -a $CLASSN.class`" ] ; then
-        # class is not in CLASSPATH
-        if [ -e "$CLASSP/$CLASSN.class" ] ; then
-                # append dir of class to CLASSPATH
-                if [ -z "${CLASSPATH}" ] ; then
-                        export CLASSPATH=$CLASSP
-                else
-                        export CLASSPATH=$CLASSP:$CLASSPATH
-                fi
-        else
-                # uh! now we would have to create a symbolic link - really
-                # ugly, i.e. print a message that one has to change the setup
-                echo "Hey! This is not a good setup to run $1 !"
-                exit 1
-        fi
+CLASS=$1
+FQCLASS=`/usr/local/bin/javaclassname $1`
+FQCLASSN=`echo $FQCLASS | sed -e 's/^.*\.\([^.]*\)$/\1/'`
+FQCLASSP=`echo $FQCLASS | sed -e 's-\.-/-g' -e 's-^[^/]*$--' -e 's-/[^/]*$--'`
+
+# for example:
+# CLASS=Test.class
+# FQCLASS=foo.bar.Test
+# FQCLASSN=Test
+# FQCLASSP=foo/bar
+
+unset CLASSBASE
+
+declare -i LINKLEVEL=0
+
+while :; do
+	if [ "`basename $CLASS .class`" == "$FQCLASSN" ]; then
+		# See if this directory works straight off
+		cd -L `dirname $CLASS`
+		CLASSDIR=$PWD
+		cd $OLDPWD
+		if echo $CLASSDIR | grep -q "$FQCLASSP$"; then
+			CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."`
+			break;
+		fi
+		# Try dereferencing the directory name
+		cd -P `dirname $CLASS`
+		CLASSDIR=$PWD
+		cd $OLDPWD
+		if echo $CLASSDIR | grep -q "$FQCLASSP$"; then
+			CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."`
+			break;
+		fi
+		# If no other possible filename exists
+		if [ ! -L $CLASS ]; then
+			exec 1>&2
+			echo $0:
+			echo "  $CLASS should be in a" \
+			     "directory tree called $FQCLASSP"
+			exit 1
+		fi
+	fi
+	if [ ! -L $CLASS ]; then break; fi
+	# Go down one more level of symbolic links
+	let LINKLEVEL+=1
+	if [ $LINKLEVEL -gt 5 ]; then
+		exec 1>&2
+		echo $0:
+		echo "  Too many symbolic links encountered"
+		exit 1
+	fi
+	CLASS=`ls --color=no -l $CLASS | sed -e 's/^.* \([^ ]*\)$/\1/'`
+done
+
+if [ -z "$CLASSBASE" ]; then
+	if [ -z "$FQCLASSP" ]; then
+		GOODNAME=$FQCLASSN.class
+	else
+		GOODNAME=$FQCLASSP/$FQCLASSN.class
+	fi
+	exec 1>&2
+	echo $0:
+	echo "  $FQCLASS should be in a file called $GOODNAME"
+	exit 1
+fi
+
+if ! echo $CLASSPATH | grep -q "^\(.*:\)*$CLASSBASE\(:.*\)*"; then
+	# class is not in CLASSPATH, so prepend dir of class to CLASSPATH
+	if [ -z "${CLASSPATH}" ] ; then
+		export CLASSPATH=$CLASSBASE
+	else
+		export CLASSPATH=$CLASSBASE:$CLASSPATH
+	fi
 fi
-PATH=$FOO
 
 shift
-/usr/local/java/bin/java $CLASSN "$@"
+/usr/bin/java $FQCLASS "$@"
+====================== Cut here ===================
+
+
+====================== Cut here ===================
+/* javaclassname.c
+ *
+ * Extracts the class name from a Java class file; intended for use in a Java
+ * wrapper of the type supported by the binfmt_misc option in the Linux kernel.
+ *
+ * Copyright (C) 1999 Colin J. Watson <cjw44@cam.ac.uk>.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+
+/* From Sun's Java VM Specification, as tag entries in the constant pool. */
+
+#define CP_UTF8 1
+#define CP_INTEGER 3
+#define CP_FLOAT 4
+#define CP_LONG 5
+#define CP_DOUBLE 6
+#define CP_CLASS 7
+#define CP_STRING 8
+#define CP_FIELDREF 9
+#define CP_METHODREF 10
+#define CP_INTERFACEMETHODREF 11
+#define CP_NAMEANDTYPE 12
+
+/* Define some commonly used error messages */
+
+#define seek_error() error("%s: Cannot seek\n", program)
+#define corrupt_error() error("%s: Class file corrupt\n", program)
+#define eof_error() error("%s: Unexpected end of file\n", program)
+#define utf8_error() error("%s: Only ASCII 1-255 supported\n", program);
+
+char *program;
+
+long *pool;
+
+u_int8_t read_8(FILE *classfile);
+u_int16_t read_16(FILE *classfile);
+void skip_constant(FILE *classfile, u_int16_t *cur);
+void error(const char *format, ...);
+int main(int argc, char **argv);
+
+/* Reads in an unsigned 8-bit integer. */
+u_int8_t read_8(FILE *classfile)
+{
+	int b = fgetc(classfile);
+	if(b == EOF)
+		eof_error();
+	return (u_int8_t)b;
+}
+
+/* Reads in an unsigned 16-bit integer. */
+u_int16_t read_16(FILE *classfile)
+{
+	int b1, b2;
+	b1 = fgetc(classfile);
+	if(b1 == EOF)
+		eof_error();
+	b2 = fgetc(classfile);
+	if(b2 == EOF)
+		eof_error();
+	return (u_int16_t)((b1 << 8) | b2);
+}
+
+/* Reads in a value from the constant pool. */
+void skip_constant(FILE *classfile, u_int16_t *cur)
+{
+	u_int16_t len;
+	int seekerr = 1;
+	pool[*cur] = ftell(classfile);
+	switch(read_8(classfile))
+	{
+	case CP_UTF8:
+		len = read_16(classfile);
+		seekerr = fseek(classfile, len, SEEK_CUR);
+		break;
+	case CP_CLASS:
+	case CP_STRING:
+		seekerr = fseek(classfile, 2, SEEK_CUR);
+		break;
+	case CP_INTEGER:
+	case CP_FLOAT:
+	case CP_FIELDREF:
+	case CP_METHODREF:
+	case CP_INTERFACEMETHODREF:
+	case CP_NAMEANDTYPE:
+		seekerr = fseek(classfile, 4, SEEK_CUR);
+		break;
+	case CP_LONG:
+	case CP_DOUBLE:
+		seekerr = fseek(classfile, 8, SEEK_CUR);
+		++(*cur);
+		break;
+	default:
+		corrupt_error();
+	}
+	if(seekerr)
+		seek_error();
+}
+
+void error(const char *format, ...)
+{
+	va_list ap;
+	va_start(ap, format);
+	vfprintf(stderr, format, ap);
+	va_end(ap);
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	FILE *classfile;
+	u_int16_t cp_count, i, this_class, classinfo_ptr;
+	u_int8_t length;
+
+	program = argv[0];
+
+	if(!argv[1])
+		error("%s: Missing input file\n", program);
+	classfile = fopen(argv[1], "rb");
+	if(!classfile)
+		error("%s: Error opening %s\n", program, argv[1]);
+
+	if(fseek(classfile, 8, SEEK_SET))  /* skip magic and version numbers */
+		seek_error();
+	cp_count = read_16(classfile);
+	pool = calloc(cp_count, sizeof(long));
+	if(!pool)
+		error("%s: Out of memory for constant pool\n", program);
+
+	for(i = 1; i < cp_count; ++i)
+		skip_constant(classfile, &i);
+	if(fseek(classfile, 2, SEEK_CUR))	/* skip access flags */
+		seek_error();
+
+	this_class = read_16(classfile);
+	if(this_class < 1 || this_class >= cp_count)
+		corrupt_error();
+	if(!pool[this_class] || pool[this_class] == -1)
+		corrupt_error();
+	if(fseek(classfile, pool[this_class] + 1, SEEK_SET))
+		seek_error();
+
+	classinfo_ptr = read_16(classfile);
+	if(classinfo_ptr < 1 || classinfo_ptr >= cp_count)
+		corrupt_error();
+	if(!pool[classinfo_ptr] || pool[classinfo_ptr] == -1)
+		corrupt_error();
+	if(fseek(classfile, pool[classinfo_ptr] + 1, SEEK_SET))
+		seek_error();
+
+	length = read_16(classfile);
+	for(i = 0; i < length; ++i)
+	{
+		u_int8_t x = read_8(classfile);
+		if((x & 0x80) || !x)
+		{
+			if((x & 0xE0) == 0xC0)
+			{
+				u_int8_t y = read_8(classfile);
+				if((y & 0xC0) == 0x80)
+				{
+					int c = ((x & 0x1f) << 6) + (y & 0x3f);
+					if(c) putchar(c);
+					else utf8_error();
+				}
+				else utf8_error();
+			}
+			else utf8_error();
+		}
+		else if(x == '/') putchar('.');
+		else putchar(x);
+	}
+	putchar('\n');
+	free(pool);
+	fclose(classfile);
+	return 0;
+}
 ====================== Cut here ===================
 
 
@@ -116,4 +375,6 @@
 
 
 originally by Brian A. Lantz, brian@lantz.com
-heavily edited for binfmt_misc by Richard Günther.
+heavily edited for binfmt_misc by Richard Günther
+new scripts by Colin J. Watson <cjw44@cam.ac.uk>.
+
diff -u --recursive --new-file v2.3.9/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.3.9/linux/Documentation/kernel-parameters.txt	Wed Jun  2 11:32:45 1999
+++ linux/Documentation/kernel-parameters.txt	Mon Jul  5 19:52:52 1999
@@ -37,7 +37,7 @@
     SOUND	Appropriate sound system support is enabled.
     VGA 	The VGA console has been enabled.
     VT		Virtual terminal support is enabled.
-    XT		IBM PC/XT support is enabled.
+    XT		IBM PC/XT MFM hard disk support is enabled.
 
 In addition, the following text indicates that the option:
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt
--- v2.3.9/linux/Documentation/networking/arcnet-hardware.txt	Thu Jan  7 08:41:55 1999
+++ linux/Documentation/networking/arcnet-hardware.txt	Mon Jul  5 19:52:52 1999
@@ -20,14 +20,14 @@
 ARCnet is a network type which works in a way similar to popular Ethernet
 networks but which is also different in some very important ways.
 
-First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps
-(slower than Ethernet) and 100Mbps (faster than normal Ethernet).  In fact,
+First of all, you can get ARCnet cards in at least two speeds: 2.5 Mbps
+(slower than Ethernet) and 100 Mbps (faster than normal Ethernet).  In fact,
 there are others as well, but these are less common.  The different hardware
 types, as far as I'm aware, are not compatible and so you cannot wire a
-100Mbps card to a 2.5Mbps card, and so on.  From what I hear, my driver does
-work with 100Mbps cards, but I haven't been able to verify this myself,
-since I only have the 2.5Mbps variety.  It is probably not going to saturate
-your 100Mbps card.  Stop complaining :)
+100 Mbps card to a 2.5 Mbps card, and so on.  From what I hear, my driver does
+work with 100 Mbps cards, but I haven't been able to verify this myself,
+since I only have the 2.5 Mbps variety.  It is probably not going to saturate
+your 100 Mbps card.  Stop complaining. :)
 
 You also cannot connect an ARCnet card to any kind of Ethernet card and
 expect it to work.  
@@ -52,17 +52,17 @@
 useful for realtime networks.
 
 In addition, all known ARCnet cards have an (almost) identical programming
-interface.  This means that with one "arcnet" driver you can support any
-card; whereas, with Ethernet, each manufacturer uses what is sometimes a
+interface.  This means that with one ARCnet driver you can support any
+card, whereas with Ethernet each manufacturer uses what is sometimes a
 completely different programming interface, leading to a lot of different,
 sometimes very similar, Ethernet drivers.  Of course, always using the same
 programming interface also means that when high-performance hardware
-facilities like PCI busmastering DMA appear, it's hard to take advantage of
+facilities like PCI bus mastering DMA appear, it's hard to take advantage of
 them.  Let's not go into that.
 
 One thing that makes ARCnet cards difficult to program for, however, is the
 limit on their packet sizes; standard ARCnet can only send packets that are
-up to 508 bytes in length.  This is smaller than the internet "bare minimum"
+up to 508 bytes in length.  This is smaller than the Internet "bare minimum"
 of 576 bytes, let alone the Ethernet MTU of 1500.  To compensate, an extra
 level of encapsulation is defined by RFC1201, which I call "packet
 splitting," that allows "virtual packets" to grow as large as 64K each,
@@ -1005,9 +1005,9 @@
     only (the JP0 jumper is hardwired), and BNC only.
 	
 This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC,
-nowhere else, not even on the few xeroxed sheets from the manual).
+nowhere else, not even on the few Xeroxed sheets from the manual).
 
-SMC Arcnet Board Type LCS-8830-T
+SMC ARCnet Board Type LCS-8830-T
 
    ------------------------------------
   |                                    |
@@ -1070,7 +1070,7 @@
 
 DIP Switches 1-5 of SW2 encode the RAM and ROM Address Range:
 
-Switches        Ram           Rom
+Switches        RAM           ROM
 12345           Address Range  Address Range
 00000		C:0000-C:07ff	C:2000-C:3fff
 10000		C:0800-C:0fff
@@ -1170,11 +1170,11 @@
 DIP Switches:
 
 	The DIP switches accessible on the accessible end of the card while
-        it is installed, is used to set the arcnet address.  There are 8
+        it is installed, is used to set the ARCnet address.  There are 8
         switches.  Use an address from 1 to 254.
 
 	Switch No.
-	12345678	Arcnet address
+	12345678	ARCnet address
 	-----------------------------------------
 	00000000	FF  	(Don't use this!)
 	00000001	FE
@@ -1222,7 +1222,7 @@
         from the upper memory regions, and then attempting to load ARCETHER
         using these addresses.
 
-	I recommend using an arcnet memory address of 0xD000, and putting
+	I recommend using an ARCnet memory address of 0xD000, and putting
         the EMS page frame at 0xC000 while using QEMM stealth mode.  That
         way, you get contiguous high memory from 0xD100 almost all the way
         the end of the megabyte.
@@ -1687,7 +1687,7 @@
                 |____________________________________________| |__|
 
 
-UM9065L : Arcnet Controller
+UM9065L : ARCnet Controller
 
 SW 1    : Shared Memory Address and I/O Base
 
@@ -1800,7 +1800,7 @@
 J1-J5       IRQ Select
 J6-J21      Unknown (Probably extra timeouts & ROM enable ...)
 LED1        Activity LED 
-BNC         Coax connector (STAR arcnet)
+BNC         Coax connector (STAR ARCnet)
 RAM         2k of SRAM
 ROM         Boot ROM socket
 UFS         Unidentified Flying Sockets
@@ -1905,7 +1905,7 @@
 ------------------------
   - from Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
 
-This is another SMC 90C65 based arcnet card. I couldn't identify the
+This is another SMC 90C65-based ARCnet card. I couldn't identify the
 manufacturer, but it might be DataPoint, because the card has the
 original arcNet logo in its upper right corner.
 
@@ -1942,9 +1942,9 @@
 SW2 1-8:    Node ID Select
 SW3 1-5:    IRQ Select   
     6-7:    Extra Timeout
-    8  :    Rom Enable   
+    8  :    ROM Enable   
 BNC         Coax connector
-XTAL        20MHz Crystal
+XTAL        20 MHz Crystal
 
 
 Setting the Node ID
@@ -2081,11 +2081,11 @@
     6-8     Base I/O Address Select
 SW2 1-8     Node ID Select (ID0-ID7)
 J1          IRQ Select
-J2          Rom Enable
+J2          ROM Enable
 J3          Extra Timeout
 LED1        Activity LED 
-BNC         Coax connector (BUS arcnet)
-RJ          Twisted Pair Connector (daisychain)
+BNC         Coax connector (BUS ARCnet)
+RJ          Twisted Pair Connector (daisy chain)
 
 
 Setting the Node ID
@@ -2419,7 +2419,7 @@
 
 Legend:
 
-COM90C65:       Arcnet Probe
+COM90C65:       ARCnet Probe
 S1  1-8:    Node ID Select
 S2  1-3:    I/O Base Address Select
     4-6:    Memory Base Address Select
@@ -2791,7 +2791,7 @@
 SW2 1-8:    Node ID Select (ID0-ID7)
 SW3 1-5:    IRQ Select   
     6-7:    Extra Timeout
-    8  :    Rom Enable   
+    8  :    ROM Enable   
 JP1         Led connector
 BNC         Coax connector
 
@@ -3089,7 +3089,7 @@
 0 = Jumper Installed
 1 = Open
 
-Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O
+Top Jumper line Bit 7 = ROM Enable 654=Memory location 321=I/O
 
 Settings for Memory Location (Top Jumper Line)
 456     Address selected
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt
--- v2.3.9/linux/Documentation/networking/arcnet.txt	Mon Sep 14 11:32:22 1998
+++ linux/Documentation/networking/arcnet.txt	Mon Jul  5 19:52:52 1999
@@ -1,4 +1,3 @@
-
 ----------------------------------------------------------------------------
 NOTE:  See also arcnet-hardware.txt in this directory for jumper-setting
 and cabling information if you're like many of us and didn't happen to get a
@@ -92,10 +91,10 @@
 	http://www.perftech.com/ or ftp to ftp.perftech.com.
 	
 Novell makes a networking stack for DOS which includes ARCnet drivers.  Try
-ftp'ing to ftp.novell.com.
+FTPing to ftp.novell.com.
 
 You can get the Crynwr packet driver collection (including arcether.com, the
-one you'll want to use with arcnet cards) from
+one you'll want to use with ARCnet cards) from
 oak.oakland.edu:/simtel/msdos/pktdrvr. It won't work perfectly on a 386+
 without patches, though, and also doesn't like several cards.  Fixed
 versions are available on my WWW page, or via e-mail if you don't have WWW
@@ -183,7 +182,7 @@
 -----------------------
 
 Configure and rebuild Linux.  When asked, answer 'm' to "Generic ARCnet 
-support" and to support for your ARcnet chipset if you want to use the
+support" and to support for your ARCnet chipset if you want to use the
 loadable module. You can also say 'y' to "Generic ARCnet support" and 'm' 
 to the chipset support if you wish.
 
@@ -269,7 +268,7 @@
 	Arcether client, assuming you remember to load winpkt of course.
 
 LAN Manager and Windows for Workgroups: These programs use protocols that
-        are incompatible with the internet standard.  They try to pretend
+        are incompatible with the Internet standard.  They try to pretend
         the cards are Ethernet, and confuse everyone else on the network. 
         
         However, v2.00 and higher of the Linux ARCnet driver supports this
@@ -288,7 +287,7 @@
 	you're completely insane, and/or you need to build some kind of
 	hybrid network that uses both encapsulation types.
 
-OS2: I've been told it works under Warp Connect with an ARCnet driver from
+OS/2: I've been told it works under Warp Connect with an ARCnet driver from
 	SMC.  You need to use the 'arc0e' interface for this.  If you get
 	the SMC driver to work with the TCP/IP stuff included in the
 	"normal" Warp Bonus Pack, let me know.
@@ -309,7 +308,7 @@
 The ARCnet driver v2.10 ALPHA supports three protocols, each on its own
 "virtual network device":
 
-	arc0  - RFC1201 protocol, the official internet standard which just
+	arc0  - RFC1201 protocol, the official Internet standard which just
 		happens to be 100% compatible with Novell's TRXNET driver. 
 		Version 1.00 of the ARCnet driver supported _only_ this
 		protocol.  arc0 is the fastest of the three protocols (for
@@ -331,13 +330,13 @@
 		reasons yet to be determined.  (Probably it's the smaller
 		MTU that does it.)
 		
-	arc0s - The "[s]imple" RFC1051 protocol is the "previous" internet
+	arc0s - The "[s]imple" RFC1051 protocol is the "previous" Internet
 		standard that is completely incompatible with the new
 		standard.  Some software today, however, continues to
 		support the old standard (and only the old standard)
 		including NetBSD and AmiTCP.  RFC1051 also does not support
 		RFC1201's packet splitting, and the MTU of 507 is still
-		smaller than the internet "requirement," so it's quite
+		smaller than the Internet "requirement," so it's quite
 		possible that you may run into problems.  It's also slower
 		than RFC1201 by about 25%, for the same reason as arc0e.
 		
@@ -388,16 +387,16 @@
    Linux but runs the free Microsoft LANMAN Client instead.
 
    Worse, one of the Linux computers (freedom) also has a modem and acts as
-   a router to my internet provider.  The other Linux box (insight) also has
+   a router to my Internet provider.  The other Linux box (insight) also has
    its own IP address and needs to use freedom as its default gateway.  The
-   XT (patience), however, does not have its own internet IP address and so
+   XT (patience), however, does not have its own Internet IP address and so
    I assigned it one on a "private subnet" (as defined by RFC1597).
 
    To start with, take a simple network with just insight and freedom. 
    Insight needs to:
    	- talk to freedom via RFC1201 (arc0) protocol, because I like it
 	  more and it's faster.
-	- use freedom as its internet gateway.
+	- use freedom as its Internet gateway.
 	
    That's pretty easy to do.  Set up insight like this:
    	ifconfig arc0 insight
@@ -417,20 +416,20 @@
    	/* and default gateway is configured by pppd */
    	
    Great, now insight talks to freedom directly on arc0, and sends packets
-   to the internet through freedom.  If you didn't know how to do the above,
+   to the Internet through freedom.  If you didn't know how to do the above,
    you should probably stop reading this section now because it only gets
    worse.
 
    Now, how do I add patience into the network?  It will be using LANMAN
    Client, which means I need the arc0e device.  It needs to be able to talk
    to both insight and freedom, and also use freedom as a gateway to the
-   internet.  (Recall that patience has a "private IP address" which won't
-   work on the internet; that's okay, I configured Linux IP masquerading on
+   Internet.  (Recall that patience has a "private IP address" which won't
+   work on the Internet; that's okay, I configured Linux IP masquerading on
    freedom for this subnet).
    
    So patience (necessarily; I don't have another IP number from my
    provider) has an IP address on a different subnet than freedom and
-   insight, but needs to use freedom as an internet gateway.  Worse, most
+   insight, but needs to use freedom as an Internet gateway.  Worse, most
    DOS networking programs, including LANMAN, have braindead networking
    schemes that rely completely on the netmask and a 'default gateway' to
    determine how to route packets.  This means that to get to freedom or
@@ -449,7 +448,7 @@
    
    This way, freedom will send all packets for patience through arc0e,
    giving its IP address as gatekeeper (on the private subnet).  When it
-   talks to insight or the internet, it will use its "freedom" internet IP
+   talks to insight or the Internet, it will use its "freedom" Internet IP
    address.
    
    You will notice that we haven't configured the arc0e device on insight. 
@@ -473,7 +472,7 @@
    
                                                     
           [RFC1201 NETWORK]                   [ETHER-ENCAP NETWORK]
-      (registered internet subnet)           (RFC1597 private subnet)
+      (registered Internet subnet)           (RFC1597 private subnet)
   
                              (IP Masquerade)
           /---------------\         *            /---------------\
@@ -523,7 +522,7 @@
 Once the driver is running, you can run the arcdump shell script (available
 from me or in the full ARCnet package, if you have it) as root to list the
 contents of the arcnet buffers at any time.  To make any sense at all out of
-this, you should grab the pertinent RFC's. (some are listed near the top of
+this, you should grab the pertinent RFCs. (some are listed near the top of
 arcnet.c).  arcdump assumes your card is at 0xD0000.  If it isn't, edit the
 script.
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/baycom.txt linux/Documentation/networking/baycom.txt
--- v2.3.9/linux/Documentation/networking/baycom.txt	Sun Jun  7 11:13:44 1998
+++ linux/Documentation/networking/baycom.txt	Tue Jul  6 19:16:55 1999
@@ -31,7 +31,7 @@
   Its devices are called bcp0 through bcp3.
 
 baycom_epp:
-  This driver supports the epp modem.
+  This driver supports the EPP modem.
   Its devices are called bce0 through bce3.
   This driver is work-in-progress.
 
@@ -60,10 +60,10 @@
         an additional power supply. Furthermore, it incorporates a carrier
         detect circuitry.
 
-epp:    This is a high speed modem adaptor that connects to an enhanced parallel port.
+EPP:    This is a high-speed modem adaptor that connects to an enhanced parallel port.
         Its target audience is users working over a high speed hub (76.8kbit/s).
 
-eppfpga: This is a redesign of the epp adaptor.
+eppfpga: This is a redesign of the EPP adaptor.
 
 
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt
--- v2.3.9/linux/Documentation/networking/cs89x0.txt	Fri Sep 11 11:21:57 1998
+++ linux/Documentation/networking/cs89x0.txt	Tue Jul  6 19:16:55 1999
@@ -203,7 +203,7 @@
 * io=###              - specify IO address (200h-360h)
 * irq=##              - specify interrupt level
 * mmode=#####         - specify memory base address
-* dma=#               - specify dma channel
+* dma=#               - specify DMA channel
 * media=rj45          - specify media type
    or media=2
    or media=aui
@@ -412,33 +412,33 @@
 assigned during hardware configuration.  The following tests are performed:
 
    * IO Register Read/Write Test
-     The IO Register Read/Write test insures that the CS8900/20 can be 
+     The IO Register Read/Write test ensures that the CS8900/20 can be 
      accessed in IO mode, and that the IO base address is correct.
 
    * Shared Memory Test
-     The Shared Memory test insures the CS8900/20 can be accessed in memory 
+     The Shared Memory test ensures the CS8900/20 can be accessed in memory 
      mode and that the range of memory addresses assigned does not conflict 
      with other devices in the system.
 
    * Interrupt Test
-     The Interrupt test insures there are no conflicts with the assigned IRQ
+     The Interrupt test ensures there are no conflicts with the assigned IRQ
      signal.
 
    * EEPROM Test
-     The EEPROM test insures the EEPROM can be read.
+     The EEPROM test ensures the EEPROM can be read.
 
    * Chip RAM Test
-     The Chip RAM test insures the 4K of memory internal to the CS8900/20 is
+     The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is
      working properly.
 
    * Internal Loop-back Test
-     The Internal Loop Back test insures the adapter's transmitter and 
+     The Internal Loop Back test ensures the adapter's transmitter and 
      receiver are operating properly.  If this test fails, make sure the 
      adapter's cable is connected to the network (check for LED activity for 
      example).
 
    * Boot PROM Test
-     The Boot PROM  test insures the Boot PROM is present, and can be read.
+     The Boot PROM test ensures the Boot PROM is present, and can be read.
      Failure indicates the Boot PROM  was not successfully read due to a
      hardware problem or due to a conflicts on the Boot PROM address
      assignment. (Test only applies if the adapter is configured to use the
@@ -564,7 +564,7 @@
 Telephone  :(800) 888-5016 (from inside U.S. and Canada)
            :(512) 442-7555 (from outside the U.S. and Canada)
 Fax	   :(512) 912-3871
-Email	   :ethernet@crystal.cirrus.com
+E-mail	   :ethernet@crystal.cirrus.com
 WWW        :http://www.crystal.com
 
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/olympic.txt linux/Documentation/networking/olympic.txt
--- v2.3.9/linux/Documentation/networking/olympic.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/olympic.txt	Mon Jul  5 19:54:55 1999
@@ -0,0 +1,75 @@
+
+IBM PCI Pit/Pit-Phy/Olympic CHIPSET BASED TOKEN RING CARDS README
+
+Release 0.2.0 - Release    
+	June 8th 1999 Peter De Schrijver & Mike Phillips
+
+
+Thanks:
+Erik De Cock, Adrian Bridgett and Frank Fiene for their 
+patience and testing.  
+Paul Norton without whose tr.c code we would have had
+a lot more work to do.
+ 
+Options:
+
+The driver accepts three options: ringspeed, pkt_buf_sz, and  
+message_level.
+
+These options can be specified differently for each card found. 
+
+ringspeed:  Has one of three settings 0 (default), 4 or 16.  0 will 
+make the card autosense the ringspeed and join at the appropriate speed, 
+this will be the default option for most people.  4 or 16 allow you to 
+explicitly force the card to operate at a certain speed.  The card will fail 
+if you try to insert it at the wrong speed. (Although some hubs will allow 
+this so be *very* careful).  The main purpose for explicitly setting the ring
+speed is for when the card is first on the ring.  In autosense mode, if the card
+cannot detect any active monitors on the ring it will not open, so you must 
+re-init the card at the appropriate speed.  Unfortunately at present the only
+way of doing this is rmmod and insmod which is a bit tough if it is compiled
+in the kernel.
+
+pkt_buf_sz:  This is this initial receive buffer allocation size.  This will
+default to 4096 if no value is entered. You may increase performance of the 
+driver by setting this to a value larger than the network packet size, although
+the driver now re-sizes buffers based on MTU settings as well. 
+
+message_level: Controls level of messages created by the driver. Defaults to 0:
+which only displays start-up and critical messages.  Presently any non-zero 
+value will display all soft messages as well.  NB This does not turn 
+debuging messages on, that must be done by modified the source code.
+
+Multi-card:
+
+The driver will detect multiple cards and will work with shared interrupts,
+each card is assigned the next token ring device, i.e. tr0 , tr1, tr2.  The 
+driver should also happily reside in the system with other drivers.  It has 
+been tested with ibmtr.c running, and I personnally have had one Olicom PCI 
+card and two IBM olympic cards (all on the same interrupt), all running
+together. 
+
+Variable MTU size:
+
+The driver can handle a MTU size upto either 4500 or 18000 depending upon 
+ring speed.  The driver also changes the size of the receive buffers as part
+of the mtu re-sizing, so if you set mtu = 18000, you will need to be able
+to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring 
+position = 296,000 bytes of memory space, plus of course anything 
+necessary for the tx sk_buff's.  Remember this is per card, so if you are
+building routers, gateway's etc, you could start to use a lot of memory
+real fast.
+
+Network Monitor Mode:
+
+By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the 
+source code the driver will implement a quasi network monitoring 
+mode.  All unexpected MAC frames (beaconing etc.) will be received
+by the driver and the source and destination addresses printed. 
+Also an entry will be added in  /proc/net called olympic_tr. This 
+displays low level information about the configuration of the ring and
+the adapter. This feature has been designed for network adiministrators
+to assist in the diagnosis of network / ring problems.
+
+6/8/99 Peter De Schrijver and Mike Phillips
+
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/policy-routing.txt linux/Documentation/networking/policy-routing.txt
--- v2.3.9/linux/Documentation/networking/policy-routing.txt	Thu May 14 10:26:22 1998
+++ linux/Documentation/networking/policy-routing.txt	Tue Jul  6 19:05:48 1999
@@ -83,7 +83,7 @@
 2.	Opposite case. Just forget all that you know about routing
 	tables. Every rule is supplied with its own gateway, device
 	info. record. This approach is not appropriate for automated
-	route maintanance, but it is ideal for manual configuration.
+	route maintenance, but it is ideal for manual configuration.
 
 	HOWTO:  iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ]
 		[ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ]
diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/z8530drv.txt linux/Documentation/networking/z8530drv.txt
--- v2.3.9/linux/Documentation/networking/z8530drv.txt	Wed May 20 18:54:34 1998
+++ linux/Documentation/networking/z8530drv.txt	Tue Jul  6 19:05:48 1999
@@ -252,7 +252,7 @@
 
 speed 1200		# the default baudrate
 clock dpll		# clock source: 
-			# 	dpll     = normal halfduplex operation
+			# 	dpll     = normal half duplex operation
 			# 	external = MODEM provides own Rx/Tx clock
 			#	divider  = use full duplex divider if
 			#		   installed (1)
diff -u --recursive --new-file v2.3.9/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt
--- v2.3.9/linux/Documentation/oops-tracing.txt	Tue Jan  5 11:14:24 1999
+++ linux/Documentation/oops-tracing.txt	Thu Jul  1 10:54:31 1999
@@ -1,15 +1,16 @@
 Quick Summary
 -------------
 
-cd /usr/src/linux/scripts/ksymoops
-make ksymoops
-./ksymoops < the_oops.txt
+Install ksymoops from ftp://ftp.ocs.com.au/pub/ksymoops
+Read the ksymoops man page.
+ksymoops < the_oops.txt
 
 and send the output the maintainer of the kernel area that seems to be
-involved with the problem. Don't worry too much about getting the wrong
-person. If you are unsure send it to the person responsible for the code
-relevant to what you were doing. If it occurs repeatably try and describe
-how to recreate it. Thats worth even more than the oops
+involved with the problem, not to the ksymoops maintainer. Don't worry
+too much about getting the wrong person. If you are unsure send it to
+the person responsible for the code relevant to what you were doing.
+If it occurs repeatably try and describe how to recreate it. Thats
+worth even more than the oops
 
 If you are totally stumped as to whom to send the report, send it to 
 linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as
@@ -41,9 +42,8 @@
 same compiler and similar setups.
 
 The other thing to do is disassemble the "Code:" part of the bug report: 
-ksymoops will do this too with the correct tools (and new version of 
-ksymoops), but if you don't have the tools you can just do a silly 
-program:
+ksymoops will do this too with the correct tools, but if you don't have
+the tools you can just do a silly program:
 
 	char str[] = "\xXX\xXX\xXX...";
 	main(){}
diff -u --recursive --new-file v2.3.9/linux/Documentation/parport.txt linux/Documentation/parport.txt
--- v2.3.9/linux/Documentation/parport.txt	Fri Mar 26 13:23:24 1999
+++ linux/Documentation/parport.txt	Sun Jul  4 10:14:13 1999
@@ -28,8 +28,8 @@
 
 to tell the parport code that you want three PC-style ports, one at
 0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an
-auto-detected IRQ.  Currently, PC-style (parport_pc) and Sun Ultra/AX
-(parport_ax) hardware is supported; more is in the works.
+auto-detected IRQ.  Currently, PC-style (parport_pc), Sun Ultra/AX
+(parport_ax), Amiga, Atari, and MFC3 hardware is supported.
 
 
 KMod
@@ -38,7 +38,7 @@
 If you use kmod, you will find it useful to edit /etc/conf.modules.
 Here is an example of the lines that need to be added:
 
-	alias parport_lowlevel parport_pc
+	post-install parport modprobe -k parport_pc
 	options parport_pc io=0x378,0x278 irq=7,auto
 
 KMod will then automatically load parport_pc (with the options
@@ -49,20 +49,15 @@
 Parport probe [optional]
 -------------
 
-Once the architecture-dependent part of the parport code is loaded
-into the kernel, you can insert the parport_probe module with:
-
-	# insmod parport_probe.o
-
-This will perform an IEEE1284 probe of any attached devices and log a
-message similar to:
+In 2.2 kernels there was a module called parport_probe, which was used
+for collecting IEEE 1284 device ID information.  This has now been
+enhanced and now lives with the IEEE 1284 support.  When a parallel
+port is detected, the devices that are connected to it are analysed,
+and information is logged like this:
 
 	parport0: Printer, BJC-210 (Canon)
 
-(If you are using kmod and have configured parport_probe as a module,
-this will just happen.)
-
-The probe information is available in /proc/parport/?/autoprobe.
+The probe information is available from files in /proc/sys/dev/parport/.
 
 
 Parport linked into the kernel statically
@@ -85,29 +80,74 @@
 ==============
 
 If you have configured the /proc filesystem into your kernel, you will
-see a new directory entry: /proc/parport.  In there will be a
+see a new directory entry: /proc/sys/dev/parport.  In there will be a
 directory entry for each parallel port for which parport is
-configured.  In each of those directories are four files describing
-that parallel port.  For example:
-
-File:				Contents:
-
-/proc/parport/0/devices		A list of the device drivers using
-				that port.  A "+" will appear by the
-				name of the device currently using the
-				port (it might not appear against any).
-
-/proc/parport/0/hardware	Parallel port's base address, IRQ line
-				and DMA channel.
-
-/proc/parport/0/irq		The IRQ that parport is using for that
-				port.  This is in a separate file to
-                                allow you to alter it by writing a new
-				value in (IRQ number or "none").
+configured.  In each of those directories are a collection of files
+describing that parallel port.
 
-/proc/parport/0/autoprobe	Any IEEE-1284 device ID information
-				that has been acquired.
+The /proc/sys/dev/parport directory tree looks like:
 
+parport
+|-- default
+|   |-- spintime
+|   `-- timeslice
+|-- parport0
+|   |-- autoprobe
+|   |-- autoprobe0
+|   |-- autoprobe1
+|   |-- autoprobe2
+|   |-- autoprobe3
+|   |-- devices
+|   |   |-- active
+|   |   `-- lp
+|   |       `-- timeslice
+|   |-- hardware
+|   `-- spintime
+`-- parport1
+    |-- autoprobe
+    |-- autoprobe0
+    |-- autoprobe1
+    |-- autoprobe2
+    |-- autoprobe3
+    |-- devices
+    |   |-- active
+    |   `-- ppa
+    |       `-- timeslice
+    |-- hardware
+    `-- spintime
+
+
+File:		Contents:
+
+devices/active	A list of the device drivers using that port.  A "+"
+		will appear by the name of the device currently using
+		the port (it might not appear against any).  The
+		string "none" means that there are no device drivers
+		using that port.
+
+hardware	Parallel port's base address, IRQ line and DMA channel.
+
+autoprobe	Any IEEE-1284 device ID information that has been
+		acquired from the (non-IEEE 1284.3) device.
+
+autoprobe[0-3]	IEEE 1284 device ID information retrieved from
+		daisy-chain devices that conform to IEEE 1284.3.
+
+spintime	The number of microseconds to busy-loop while waiting
+		for the peripheral to respond.  You might find that
+		adjusting this improves performance, depending on your
+		peripherals.  This is a port-wide setting, i.e. it
+		applies to all devices on a particular port.
+
+timeslice	The number of jiffies (FIXME: this should be in
+		milliseconds or something) that a device driver is
+		allowed to keep a port claimed for.  This is advisory,
+		and driver can ignore it if it must.
+
+default/*	The defaults for spintime and timeslice. When a new
+		port is	registered, it picks up the default spintime.
+		When a new device is registered, it picks up the
+		default timeslice.
 
 Device drivers
 ==============
@@ -135,7 +175,7 @@
 
 Also:
 
- * If you selected the IEEE-1284 autoprobe at compile time, you can say
+ * If you selected the IEEE 1284 support at compile time, you can say
    `lp=auto' on the kernel command line, and lp will create devices
    only for those ports that seem to have printers attached.
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/pcwd-watchdog.txt linux/Documentation/pcwd-watchdog.txt
--- v2.3.9/linux/Documentation/pcwd-watchdog.txt	Sun Jan 19 05:47:24 1997
+++ linux/Documentation/pcwd-watchdog.txt	Tue Jul  6 19:05:48 1999
@@ -1,6 +1,6 @@
                      Berkshire Products PC Watchdog Card
                    Support for ISA Cards  Revision A and C
-           Documentation and Driver by Ken Hollis <khollis@nurk.org>
+           Documentation and Driver by Ken Hollis <kenji@bitgate.com>
 
  The PC Watchdog is a card that offers the same type of functionality that
  the WDT card does, only it doesn't require an IRQ to run.  Furthermore,
@@ -15,7 +15,7 @@
  The Watchdog Driver will automatically find your watchdog card, and will
  attach a running driver for use with that card.  After the watchdog
  drivers have initialized, you can then talk to the card using the PC
- Watchdog program, available from ftp.bitgate.com:/pub/bitgate/pcwd.
+ Watchdog program, available from http://ftp.bitgate.com/pcwd/.
 
  I suggest putting a "watchdog -d" before the beginning of an fsck, and
  a "watchdog -e -t 1" immediately after the end of an fsck.  (Remember
@@ -128,4 +128,7 @@
  And that's all she wrote!
 
  -- Ken Hollis
-    (khollis@nurk.org)
+    (kenji@bitgate.com)
+
+(This documentation may be out of date.  Check
+ http://ftp.bitgate.com/pcwd/ for the absolute latest additions.)
diff -u --recursive --new-file v2.3.9/linux/Documentation/sound/Introduction linux/Documentation/sound/Introduction
--- v2.3.9/linux/Documentation/sound/Introduction	Thu Apr 29 11:53:41 1999
+++ linux/Documentation/sound/Introduction	Mon Jul  5 20:04:47 1999
@@ -1,6 +1,6 @@
-Soundcore	Notes on Modular Sound Drivers and Soundcore
+Introduction	Notes on Modular Sound Drivers and Soundcore
 Wade Hampton 
-11/20/1998
+6/30/1999
 
 Purpose:  
 ========
@@ -10,13 +10,21 @@
 
 Note, some of this probably should be added to the Sound-HOWTO!
 
+
 Copying:
 ========
 none
 
+
 History:
 ========
-0.1.0  11/20/1998  First version
+0.1.0  11/20/1998  First version, draft
+1.0.0  11/1998     Alan Cox changes, incorporation in 2.2.0
+                   as /usr/src/linux/Documentation/sound/Introduction
+1.1.0  6/30/1999   Second version, added notes on making the drivers,
+                   added info on multiple sound cards of similar types,]
+                   added more diagnostics info, added info about esd.
+                   added info on OSS and ALSA.
 
 
 Modular Sound Drivers:
@@ -58,6 +66,53 @@
 for the same or a similar feature (dma1= versus dma16=).  As a last 
 resort, inspect the code (search for MODULE_PARM).
 
+Notes:
+
+1.  There is a new OpenSource sound driver called ALSA which is
+    currently under development:  http://www.alsa-project.org/
+    I have not tried it nor am I aware of its status, but it is
+    currently under development.
+
+2.  The commercial OSS driver may be obtained from the site:
+    http://www/opensound.com.  This may be used for cards that
+    are unsupported by the kernel driver, or may be used
+    by other operating systems.  
+
+3.  The enlightenment sound daemon may be used for playing
+    multiple sounds at the same time via a single card, eliminating
+    some of the requirements for multiple sound card systems.  For
+    more information, see:  http://www.tux.org/~ricdude/EsounD.html  
+    The "esd" program may be used with the real-player and mpeg 
+    players like mpg123 and x11amp.
+
+
+Building the Modules:
+=====================
+
+This document does not provide full details on building the 
+kernel, etc.  The notes below apply only to making the kernel
+sound modules.   If this conflicts with the kernel's README,
+the README takes precedence. 
+
+1.  To make the kernel sound modules, cd to your /usr/src/linux
+    directory (typically) and type make config, make menuconfig, 
+    or make xconfig (to start the command line, dialog, or x-based
+    configuration tool).  
+
+2.  Select the Sound option and a dialog will be displayed.  
+
+3.  Select M (module) for "Sound card support".
+
+4.  Select your sound driver(s) as a module.  For ProAudio, Sound
+    Blaster, etc., select M (module) for OSS sound modules.
+    [thanks to marvin stodolsky <stodolsk@erols.com>]A
+
+5.  Make the kernel (e.g., make dep ; make bzImage), and install
+    the kernel.
+
+6.  Make the modules and install them (make modules; make modules_install).
+
+
 
 INSMOD:
 =======
@@ -82,6 +137,9 @@
 /sbin/insmod uart401
 /sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP
 
+When using sound as a module, I typically put these commands
+in a file such as /root/soundon.sh.
+
 
 MODPROBE:
 =========
@@ -117,8 +175,8 @@
 	soundcore               1968   8  [sb sound]
 
 
-Removing Sound:
-===============
+Removing Sound: 
+=============== 
 
 Sound may be removed by using /sbin/rmmod in the reverse order
 in which you load the modules.  Note, if a program has a sound device
@@ -134,6 +192,25 @@
 /sbin/rmmod soundlow
 /sbin/rmmod soundcore
 
+When using sound as a module, I typically put these commands
+in a script such as /root/soundoff.sh.
+
+
+Removing Sound for use with OSS: 
+================================ 
+
+If you get really stuck or have a card that the kernel modules
+will not support, you can get a commercial sound driver from
+http://www.opensound.com.  Before loading the commercial sound
+driver, you should do the following:
+
+1.  remove sound modules (detailed above)
+2.  remove the sound modules from /etc/conf.modules
+3.  move the sound modules from /lib/modules/<kernel>/misc
+    (for example, I make a /lib/modules/<kernel>/misc/tmp
+    directory and copy the sound module files to that 
+    directory).
+
 
 Multiple Sound Cards:
 =====================
@@ -154,11 +231,30 @@
 first (in my case "sb") and then load the other one
 (in my case "cs4232").
 
+If you have two cards of the same type that are jumpered 
+cards or different PnP revisions, you may load the same 
+module twice.  For example, I have a SoundBlaster vibra 16
+and an older SoundBlaster 16 (jumpers).  To load the module
+twice, you need to do the following:
+
+1.  Copy the sound modules to a new name.  For example
+    sb.o could be copied (or symlinked) to sb1.o for the
+    second SoundBlasster.
+
+2.  Make a second entry in /etc/conf.modules, for example,
+    sound1 or sb1.  This second entry should refer to the
+    new module names for example sb1, and should include
+    the I/O, etc. for the second sound card.
+
+3.  Update your soundon.sh script, etc.
+
 Warning:  I have never been able to get two PnP sound cards of the
 same type to load at the same time.  I have tried this several times
 with the Soundblaster Vibra 16 cards.  OSS has indicated that this
 is a PnP problem....  If anyone has any luck doing this, please 
-send me an E-MAIL.  PCI sound cards should not have this problem.
+send me an E-MAIL.  PCI sound cards should not have this problem.a
+Since this was originally release, I have received a couple of 
+mails from people who have accomplished this!
 
 
 Sound Problems:
@@ -175,6 +271,8 @@
       write down what addresses, IRQ, and DMA channels
       those were using for the same hardware.  You probably 
       can use these addresses, IRQs, and DMA channels.
+      You should really do this BEFORE attempting to get
+      sound working!
   
   B)  Check (cat) /proc/interrupts, /proc/ioports,
       and /proc/dma.  Are you trying to use an address,
@@ -184,22 +282,44 @@
       may need a kernel patch to get this device).
   
   D)  Inspect your /var/log/messages file.  Often that will 
-      indicate what IRQ or IO port could not be obtained
+      indicate what IRQ or IO port could not be obtained.
   
   E)  Try another port or IRQ.  Note this may involve 
       using the PnP tools to move the sound card to 
-      another location.
+      another location.  Sometimes this is the only way 
+      and it is more or less trial and error.
 
-2)  If you get motorboating (the same sound or part of a 
+2)  If you get motor-boating (the same sound or part of a 
     sound clip repeated), you probably have either an IRQ
-    or DMA conflict.  Move the card to another address.  This
-    has happened to me when playing long files when I had 
-    an IRQ conflict.
+    or DMA conflict.  Move the card to another IRQ or DMA
+    port.  This has happened to me when playing long files 
+    when I had an IRQ conflict.
+
+3.  If you get dropouts or pauses when playing high sample
+    rate files such as using mpg123 or x11amp/xmms, you may 
+    have too slow of a CPU and may have to use the options to 
+    play the files at 1/2 speed.  For example, you may use
+    the -2 or -4 option on mpg123.  You may also get this
+    when trying to play mpeg files stored on a CD-ROM
+    (my Toshiba T8000 PII/366 sometimes has this problem).
+
+4.  If you get "cannot access device" errors, your /dev/dsp
+    files, etc. may be set to owner root, mode 600.  You 
+    may have to use the command:
+      chmod 666 /dev/dsp /dev/mixer /dev/audio
+
+5.  If you get "device busy" errors, another program has the
+    sound device open.  For example, if using the Enlightenment
+    sound daemon "esd", the "esd" program has the sound device.
+    If using "esd", please RTFM the docs on ESD.  For example,
+    esddsp <program> may be used to play files via a non-esd
+    aware program.
+
 
-3)  Ask for help on the sound list or send E-MAIL to the
+6)  Ask for help on the sound list or send E-MAIL to the
     sound driver author/maintainer.
 
-4)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
+7)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
 
 
 Configuring Sound:
@@ -210,7 +330,8 @@
 1)  Hardcoded in the kernel at compile time (not applicable when
     using sound modules).  This was the OLD way!
 
-2)  On the command line when using insmod.
+2)  On the command line when using insmod or in a bash script
+    using command line calls to load sound.
 
 3)  In /etc/conf.modules when using modprobe.
 
@@ -224,7 +345,6 @@
 Anyone want to write a linuxconf module for configuring sound?
 
 
-
 For More Information (RTFM):
 ============================
 1)  Information on kernel modules:  linux/Documentation/modules.txt
@@ -242,12 +362,17 @@
 
 7)  The sndconfig and rhsound documentation from Red Hat.
 
-8)  The Linux-sound mailing list:  sound-list@redhat.com
+8)  The Linux-sound mailing list:  sound-list@redhat.com.
+
+9)  Enlightenment documentation (for info on esd)
+    http://www.tux.org/~ricdude/EsounD.html.
 
+10) ALSA home page:  http://www.alsa-project.org/
 
 
 Contact Information:
 ====================
 Wade Hampton:  (whampton@staffnet.com)
+
 
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2
--- v2.3.9/linux/Documentation/sound/OPL3-SA2	Thu Jan 14 22:53:02 1999
+++ linux/Documentation/sound/OPL3-SA2	Mon Jul  5 20:04:47 1999
@@ -46,6 +46,21 @@
 then email me if you are willing to experiment in an effort to make it
 work.
 
+************************************************************************
+* I have now had two such machines, and I have fixed this to work
+* properly when built into the kernel.  The Toshiba Libretto series, or
+* at least models 70CT and 110CT which I have owned, use a Yamaha
+* OPL3-SAx (OPL3-SA3 according to documentation) sound chip, IRQ 5,
+* IO addresses 220/530/388/330/370 and DMA 1,0 (_not_ 0,1).  All these
+* configuration settings can be gathered by booting another OS which
+* recognizes the card already.
+*
+* I have made things 'just work' for the non-modular case on such
+* machines when configured properly.
+*
+* David Luyer <luyer@ucs.uwa.edu.au>
+************************************************************************
+
 If you are using isapnp, follow the directions in its documentation to
 produce a configuration file.  Here is the relevant excerpt I use for
 my SAx card from my isapnp.conf:
diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/README linux/Documentation/sysctl/README
--- v2.3.9/linux/Documentation/sysctl/README	Mon Apr 12 10:10:27 1999
+++ linux/Documentation/sysctl/README	Mon Jul  5 20:04:47 1999
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/		kernel version 2.2.5
+Documentation for /proc/sys/		kernel version 2.2.10
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 'Why', I hear you ask, 'would anyone even _want_ documentation
diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/fs.txt linux/Documentation/sysctl/fs.txt
--- v2.3.9/linux/Documentation/sysctl/fs.txt	Mon Apr 12 10:10:27 1999
+++ linux/Documentation/sysctl/fs.txt	Mon Jul  5 20:04:47 1999
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/fs/*	kernel version 2.2.5
+Documentation for /proc/sys/fs/*	kernel version 2.2.10
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt
--- v2.3.9/linux/Documentation/sysctl/kernel.txt	Mon Apr 12 10:10:27 1999
+++ linux/Documentation/sysctl/kernel.txt	Mon Jul  5 20:04:47 1999
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/kernel/*	kernel version 2.2.5
+Documentation for /proc/sys/kernel/*	kernel version 2.2.10
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
@@ -76,12 +76,21 @@
 
 domainname & hostname:
 
-These files can be controlled to set the domainname and
-hostname of your box. For the classic darkstar.frop.org
-a simple:
+These files can be used to set the NIS/YP domainname and the
+hostname of your box in exactly the same way as the commands
+domainname and hostname, i.e.:
 # echo "darkstar" > /proc/sys/kernel/hostname
-# echo "frop.org" > /proc/sys/kernel/domainname
-would suffice to set your hostname and domainname.
+# echo "mydomain" > /proc/sys/kernel/domainname
+has the same effect as
+# hostname "darkstar" > /proc/sys/kernel/hostname
+# domainname "mydomain" > /proc/sys/kernel/domainname
+
+Note, however, that the classic darkstar.frop.org has the
+hostname "darkstar" and DNS (Internet Domain Name Server)
+domainname "frop.org", not to be confused with the NIS (Network
+Information Service) or YP (Yellow Pages) domainname. These two
+domain names are in general different. For a detailed discussion
+see the hostname(1) man page.
 
 ==============================================================
 
diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/sunrpc.txt linux/Documentation/sysctl/sunrpc.txt
--- v2.3.9/linux/Documentation/sysctl/sunrpc.txt	Mon Apr 12 10:10:27 1999
+++ linux/Documentation/sysctl/sunrpc.txt	Mon Jul  5 20:04:47 1999
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/sunrpc/*	kernel version 2.2.5
+Documentation for /proc/sys/sunrpc/*	kernel version 2.2.10
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt
--- v2.3.9/linux/Documentation/sysctl/vm.txt	Thu Apr 29 11:53:41 1999
+++ linux/Documentation/sysctl/vm.txt	Mon Jul  5 20:04:47 1999
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/vm/*	kernel version 2.2.5
+Documentation for /proc/sys/vm/*	kernel version 2.2.10
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/API.html linux/Documentation/video4linux/API.html
--- v2.3.9/linux/Documentation/video4linux/API.html	Thu Jan  7 08:41:55 1999
+++ linux/Documentation/video4linux/API.html	Mon Jul  5 20:04:47 1999
@@ -1,6 +1,9 @@
 <HTML><HEAD>
-<TITLE>Video4Linux Kernel API Reference v0.1:19980516</TITLE>
+<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE>
 </HEAD>
+<! Revision History: >
+<!   4/30/1999 - Fred Gleason (fredg@wava.com)>
+<! Documented extensions for the Radio Data System (RDS) extensions >
 <BODY bgcolor="#ffffff">
 <H3>Devices</H3>
 Video4Linux provides the following sets of device files. These live on the
@@ -117,7 +120,7 @@
 </TABLE>
 <P>
 Merely setting the window does not enable capturing. Overlay capturing
-is activatied by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
+is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
 disabled by passing it a value of 0. 
 <P>
 Some capture devices can capture a subfield of the image they actually see.
@@ -150,7 +153,7 @@
 nature of the channel itself.
 <P>
 The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the
-capture to this input. It is not defined whether paramters such as colour
+capture to this input. It is not defined whether parameters such as colour
 settings or tuning are maintained across a channel switch. The caller should
 maintain settings as desired for each channel. (This is reasonable as 
 different video inputs may have different properties).
@@ -249,6 +252,8 @@
 <TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD>
 <TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD>
 <TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD>
+<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD>
+<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD>
 </TABLE>
 <P>
 The following modes are defined
@@ -349,6 +354,21 @@
 <TR><TD><b>teletext</b><TD>Teletext device</TD>
 </TABLE>
 <P>
-
+<H3>RDS Datastreams</H3>
+For radio devices that support it, it is possible to receive Radio Data
+System (RDS) data by means of a read() on the device.  The data is packed in
+groups of three, as follows:
+<TABLE>
+<TR><TD>First Octet</TD><TD>Least Siginificant Byte of RDS Block</TD></TR>
+<TR><TD>Second Octet</TD><TD>Most Siginificant Byte of RDS Block
+<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit.  Indicates that
+an uncorrectable error occured during reception of this block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bit 6:</TD><TD>Corrected bit.  Indicates that  
+an error was corrected for this data block.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 5-3:</TD><TD>Reeived Offset.  Indicates the  
+offset received by the sync system.</TD></TR>
+<TR><TD>&nbsp;</TD><TD>Bits 2-0:</TD><TD>Offset Name.  Indicates the  
+offset applied to this data.</TD></TR>
+</TABLE>
 </BODY>
 </HTML>
diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/README.buz linux/Documentation/video4linux/README.buz
--- v2.3.9/linux/Documentation/video4linux/README.buz	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/README.buz	Mon Jul  5 20:04:47 1999
@@ -0,0 +1,212 @@
+Iomega Buz Driver for Linux
+===========================
+
+by Rainer Johanni <Rainer@Johanni.de>
+
+Compiling and Loading the Driver
+================================
+
+You must run a 2.2.x kernel in order to use this driver.
+
+To compile the driver, just type make.
+
+Besides the files in this directory, the driver needs the
+'videodev' and the 'i2c' module from the Linux kernel.
+In order to get these modules available, enable module support
+for VIDEODEV and BTTV (which implies i2c) in your kernel
+configuration. You find these devices in the menu
+"Character Devices" in your Kernel Configuration.
+
+Before you load the driver you must have a video device
+at major device node 81. If you don't have it yet, do the
+following (as root!):
+
+cd /dev
+mknod video0 c 81 0
+ln -s video0 video
+
+Edit the 'update' script if you want to give the driver
+special options and then type (as root)
+
+./update
+
+to insert all the necessary modules into the kernel.
+
+If you want to make full use of the Video for Linux uncompressed
+grabbing facilities, you must either
+
+- obtain and install the "big_physarea patch" for your kernel and
+  set aside the necessary memory during boot time.
+  There seem to be several versions of this patch against
+  various kernel versions floating around in the net,
+  you may obtain one e.g. from:
+  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz
+  You also have to compile your driber AFTER installing that patch
+  in order to get it working
+
+  or
+
+- start your kernel with the mem=xxx option, where xxx is your
+  real memory minus the memory needed for the buffers.
+  For doing this add an entry in lilo.conf (if you use lilo):
+    append "mem=xxxM"
+  or add a line in your linux.par file (if you use loadlin):
+    mem=xxxM
+
+The second method is by far easier, however it is dangerous
+if more than one driver at a time has the idea to use the memory
+leftover by setting the mem=xxx parameter below the actual
+memory size.
+
+Read also below how to use this memory!
+
+
+
+Driver Options
+==============
+
+You are able to customize the behavior of the driver by giving
+it some options at start time.
+
+default_input, default_norm
+---------------------------
+
+As soon as the driver is loaded, the Buz samples video signals
+from one of its input ports and displays it on its output.
+The driver uses the Composite Input and the video norm PAL for this.
+If you want to change this default behavior, set default_input=1
+(for S-VHS input) or default_norm=1 for NTSC.
+
+v4l_nbufs, v4l_bufsize
+----------------------
+
+In order to make to make full use of the Video for Linux picture
+grabbing facilities of the driver (which are needed by many
+Video for Linux applications), the driver needs a set of
+physically contiguous buffers for grabbing. These parameters
+determine how many buffers of which size the driver will
+allocate at open (the open will fail if it is unable to do so!).
+
+These values do not affect the MJPEG grabbing facilities of the driver,
+they are needed for uncompressed image grabbing only!!!
+
+v4l_nbufs is the number of buffers to allocate, a value of 2 (the default)
+should be sufficient in allmost all cases. Only special applications
+(streaming captures) will need more buffers and then mostly the
+MJPEG capturing features of the Buz will be more apropriate.
+So leave this parameter at it's default unless you know what you do.
+
+The things for v4l_bufsize are more complicated:
+v4l_bufsize is set by default to 128 [KB] which is the maximum
+amount of physically contiguous memory Linux is able to allocate
+without kernel changes. This is sufficient for grabbing 24 bit color images
+up to sizes of approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072).
+
+In order to be able to capture bigger images you have either to
+- obtain and install the "big_physarea patch" and set aside
+  the necessary memory during boot time or
+- start your kernel with the mem=xxx option, where xxx is your
+  real memory minus the memory needed for the buffers.
+In that case, usefull settings for v4l_bufsize are
+- 1296 [Kb] for grabbing 24 bit images of max size 768*576
+- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!)
+You may reduce these numbers accordingly if you know you are only
+grabbing 720 pixels wide images or NTSC images (max height 480).
+
+In some cases it may happen that Linux isn't even able to obtain
+the default 128 KB buffers. If you don't need uncompressed image
+grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4)
+in order to be able to open the video device.
+
+vidmem
+------
+
+The video mem address of the video card.
+The driver has a little database for some videocards
+to determine it from there. If your video card is not in there
+you have either to give it to the driver as a parameter
+or set in in a VIDIOCSFBUF ioctl
+
+The videocard database is contained in the file "videocards.h"
+Gernot Ziegler wants to keep an actual version of that file.
+If your card is not contained in that file, look at
+http://www.lysator.liu.se/~gz/buz/ for an actual version of
+"videocards.h".
+
+triton, natoma
+--------------
+
+The driver tries to detect if you have a triton or natome chipset
+in order to take special messures for these chipsets.
+If this detection fails but you are sure you have such a chipset,
+set the corresponding variable to 1.
+This is a very special option and may go away in the future.
+
+
+
+Programming interface
+=====================
+
+This driver should be fully compliant to Video for Linux, so all
+tools working with Video for Linux should work with (hopefully)
+no problems.
+
+A description of the Video for Linux programming interace can be found at:
+http://roadrunner.swansea.linux.org.uk/v4lapi.shtml
+
+Besides the Video for Linux interface, the driver has a "proprietary"
+interface for accessing the Buz's MJPEG capture and playback facilities.
+
+The ioctls for that interface are as follows:
+
+BUZIOC_G_PARAMS
+BUZIOC_S_PARAMS
+
+Get and set the parameters of the buz. The user should allways
+do a BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default
+settings, change what he likes and then make a BUZIOC_S_PARAMS call.
+A typical application should at least set the members
+input, norm and decimation of the struct buz_params.
+For a full description of all members see "buz.h"
+
+BUZIOC_REQBUFS
+
+Before being able to capture/playback, the user has to request
+the buffers he is wanting to use. Fill the structure
+buz_requestbuffers with the size (recommended: 256*1024) and
+the number (recommended 32 up to 256). There are no such restrictions
+as for the Video for Linux buffers, you should LEAVE SUFFICIENT
+MEMORY for your system however, else strange things will happen ....
+On return, the buz_requestbuffers structure contains number and
+size of the actually allocated buffers.
+You should use these numbers for doing a mmap of the buffers
+into the user space.
+The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap
+maps the MJPEG buffer instead of the V4L buffers.
+
+BUZIOC_QBUF_CAPT
+BUZIOC_QBUF_PLAY
+
+Queue a buffer for capture or playback. The first call also starts
+streaming capture. When streaming capture is going on, you may
+only queue further buffers or issue syncs until streaming
+capture is switched off again with a argument of -1 to
+a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl.
+
+BUZIOC_SYNC
+
+Issue this ioctl when all buffers are queued. This ioctl will
+block until the first buffer becomes free for saving its
+data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY).
+
+BUZIOC_G_STATUS
+
+Get the status of the input lines (video source connected/norm).
+This ioctl may be subject to change.
+
+
+
+
+
+See the examples directory delivered with this driver
+for actual coding examples!
diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/bttv/PROBLEMS linux/Documentation/video4linux/bttv/PROBLEMS
--- v2.3.9/linux/Documentation/video4linux/bttv/PROBLEMS	Sun Aug 23 13:32:25 1998
+++ linux/Documentation/video4linux/bttv/PROBLEMS	Mon Jul  5 20:04:47 1999
@@ -17,9 +17,9 @@
   If this 64MB area overlaps the IO memory of the Bt848 you also have to
   remap this. E.g.: insmod bttv vidmem=0xfb0 remap=0xfa0
 
-  If the videomemory is found at the right place and there are no address
-  conflicts but still no picture (or the computer even crashes.),
-  try disabling features of your PCI chipset in the BIOS Setup.
+  If the video memory is found at the right place and there are no address
+  conflicts but still no picture (or the computer even crashes),
+  try disabling features of your PCI chipset in the BIOS setup.
 
   Frank Kapahnke <frank@kapahnke.prima.ruhr.de> also reported that problems
   with his S3 868 went away when he upgraded to XFree 3.2.
@@ -50,13 +50,13 @@
   
   Disable backing store by starting X with the option "-bs"
 
-- When using 32bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
+- When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
   can sometimes lock up if you use more than 1 bt848 card at the same time.
   You will always get pixel errors when e.g. using more than 1 card in full
   screen mode. Maybe we need something faster than the PCI bus ...
 
 
-- Some S3 cards and the Matrox Mystique will produce pixel erros with
-  full resolution in 32bit mode.
+- Some S3 cards and the Matrox Mystique will produce pixel errors with
+  full resolution in 32-bit mode.
 
-- Some video cards have problems with Accelerated X 4.1
\ No newline at end of file
+- Some video cards have problems with Accelerated X 4.1
diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/bttv/README.RADIO linux/Documentation/video4linux/bttv/README.RADIO
--- v2.3.9/linux/Documentation/video4linux/bttv/README.RADIO	Sun Aug 23 13:32:25 1998
+++ linux/Documentation/video4linux/bttv/README.RADIO	Mon Jul  5 20:04:47 1999
@@ -6,7 +6,7 @@
 
 So you should have TV with (stereo) sound now.  Radio does _not_ work.
 It probably does not work with sat receivers. I can't test this and
-therefore hav'nt added support for it yet. If someone needs this and
+therefore have not added support for it yet. If someone needs this and
 can help testing the sat stuff, drop me a note.
 
   Gerd
diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/bttv/THANKS linux/Documentation/video4linux/bttv/THANKS
--- v2.3.9/linux/Documentation/video4linux/bttv/THANKS	Sun Aug 23 13:32:25 1998
+++ linux/Documentation/video4linux/bttv/THANKS	Mon Jul  5 20:04:47 1999
@@ -17,7 +17,7 @@
   components on their cards. (E.g. how the tuner type is detected)
   Without their card I could not have debugged the NTSC mode.
 	
-- Hauppauge for telling how the sound input is selected and what compenents
+- Hauppauge for telling how the sound input is selected and what components
   they do and will use on their radio cards.
   Also many thanks for faxing me the FM1216 data sheet.
 
diff -u --recursive --new-file v2.3.9/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.9/linux/MAINTAINERS	Wed Jun 30 13:38:18 1999
+++ linux/MAINTAINERS	Tue Jul  6 19:16:55 1999
@@ -16,8 +16,8 @@
 	SMC etherpower for that.)
 
 3.	Make sure your changes compile correctly in multiple
-	configurations. In paticular check changes work both as a module
-	and built into the kernel.
+	configurations. In particular check that changes work both as a
+	module and built into the kernel.
 
 4.	When you are happy with a change make it generally available for
 	testing and await feedback.
@@ -28,7 +28,7 @@
 	and variable names.  These aren't as silly as they seem. One
 	job the maintainers (and especially Linus) do is to keep things
 	looking the same. Sometimes this means that the clever hack in
-	your driver to get around a problem actual needs to become a
+	your driver to get around a problem actually needs to become a
 	generalized kernel feature ready for next time. See 
 	Documentation/CodingStyle for guidance here.
 
@@ -49,8 +49,8 @@
 
 Maintainers List (try to look for most precise areas first)
 
-Note: For the hard of thinking, this list is meant to remain in Alphabetical
-order. If you could add yourselves to it in Alphabetical order that would
+Note: For the hard of thinking, this list is meant to remain in alphabetical
+order. If you could add yourselves to it in alphabetical order that would
 so much easier [Ed]
 
 P: Person
@@ -163,6 +163,12 @@
 W:	http://www.ife.ee.ethz.ch/~sailer/ham/ham.html
 S:	Maintained
 
+BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
+P:	Kenji Hollis
+M:	kenji@bitgate.com
+W:	http://ftp.bitgate.com/pcwd/
+S:	Maintained
+
 BUSLOGIC SCSI DRIVER
 P:	Leonard N. Zubkoff
 M:	Leonard N. Zubkoff <lnz@dandelion.com>
@@ -271,6 +277,12 @@
 L:	linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu
 S:	Maintained
 
+COMPAQ SMART2 RAID DRIVER
+P:	Charles White	
+M:	Charles White <arrays@compaq.com>
+L:	compaqandlinux@yps.org	
+S:	Maintained
+
 EATA ISA/EISA/PCI SCSI DRIVER
 P:	Dario Ballabio
 M:	dario@milano.europe.dg.com
@@ -579,6 +591,26 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+OLYMPIC NETWORK DRIVER
+P:	Peter De Shrijver
+M:	p2@ace.ulyssis.sutdent.kuleuven.ac.be	
+P:	Mike Phillips
+M:	phillim@amtrak.com
+L:	linux-net@vger.rutgers.edu
+L:	linux-tr@emissary.aus-etc.com
+W:	http://www.linuxtr.net
+S:	Maintained
+
+OLYMPIC NETWORK DRIVER
+P:	Peter De Shrijver
+M:	p2@ace.ulyssis.sutdent.kuleuven.ac.be	
+P:	Mike Phillips
+M:	phillim@amtrak.com
+L:	linux-net@vger.rutgers.edu
+L:	linux-tr@emissary.aus-etc.com
+W:	http://www.linuxtr.net
+S:	Maintained
+
 OPL3-SA2, SA3, and SAx DRIVER
 P:	Scott Murray
 M:	scottm@interlog.com
@@ -645,7 +677,7 @@
 
 REAL TIME CLOCK DRIVER
 P:	Paul Gortmaker
-M	gpg109@rsphy1.anu.edu.au
+M:	gpg109@rsphy1.anu.edu.au
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
@@ -697,9 +729,10 @@
 S:	Maintained
 
 SMB FILESYSTEM
-P:	Volker Lendecke
-M:	vl@kki.org
-L:	samba@listproc.anu.edu.au
+P:	Andrew Tridgell
+M:	tridge@samba.org
+W:	http://samba.org/
+L:	samba@samba.org
 S:	Maintained
 
 SMP: (except SPARC)
diff -u --recursive --new-file v2.3.9/linux/Makefile linux/Makefile
--- v2.3.9/linux/Makefile	Wed Jun 30 13:38:18 1999
+++ linux/Makefile	Thu Jul  1 10:54:31 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 9
+SUBLEVEL = 10
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -351,8 +351,7 @@
 
 clean:	archclean
 	rm -f kernel/ksyms.lst include/linux/compile.h
-	rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \
-		! -regex '.*ksymoops/.*' -print`
+	rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print`
 	rm -f core `find . -type f -name 'core' -print`
 	rm -f core `find . -name '.*.flags' -print`
 	rm -f vmlinux System.map
@@ -376,7 +375,6 @@
 	rm -f .version .config* config.in config.old
 	rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
 	rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
-	rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops
 	rm -f .menuconfig.log
 	rm -f include/asm
 	rm -rf include/config
diff -u --recursive --new-file v2.3.9/linux/README linux/README
--- v2.3.9/linux/README	Sun May 30 10:17:43 1999
+++ linux/README	Thu Jul  1 10:54:08 1999
@@ -9,9 +9,9 @@
 bugs.  It is *strongly* recommended that you back up the previous kernel
 before installing any new 2.3.xx release.
 
-If you need to use a proven and stable Linux kernel, please use 1.2.13,
-2.0.36 or 2.2.xx.  All features which will be in the 2.3.xx releases will
-be contained in 2.4.xx when the code base has stabilized again.
+If you need to use a proven and stable Linux kernel, please use 2.0.37
+or 2.2.xx.  All features which will be in the 2.3.xx releases will be
+contained in 2.4.xx when the code base has stabilized again. 
 
 If you decide to use 2.3, it is recommended that you join the kernel mailing
 list.  To do this, e-mail majordomo@vger.rutgers.edu, and put in the body
@@ -105,7 +105,7 @@
 
 SOFTWARE REQUIREMENTS
 
-   Compiling and running the 2.3.x kernels requires up-to-date
+   Compiling and running the 2.3.xx kernels requires up-to-date
    versions of various software packages.  Consult
    ./Documentation/Changes for the minimum version numbers required
    and how to get updates for these packages.  Beware that using
diff -u --recursive --new-file v2.3.9/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.3.9/linux/arch/alpha/config.in	Wed Jun 30 13:38:18 1999
+++ linux/arch/alpha/config.in	Thu Jul  1 14:22:56 1999
@@ -188,13 +188,7 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-  fi
-fi
+source drivers/misc/Config.in
 endmenu
 
 source drivers/pnp/Config.in
diff -u --recursive --new-file v2.3.9/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.3.9/linux/arch/alpha/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
+++ linux/arch/alpha/kernel/ptrace.c	Sun Jul  4 13:41:08 1999
@@ -135,242 +135,18 @@
 	return 0;
 }
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long
-get_long(struct task_struct * tsk, struct vm_area_struct * vma,
-	 unsigned long addr)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-	unsigned long page;
-
-	DBG(DBG_MEM_ALL, ("getting long at 0x%lx\n", addr));
- repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void
-put_long(struct task_struct * tsk, struct vm_area_struct * vma,
-	 unsigned long addr, unsigned long data)
+static inline int
+read_int(struct task_struct *task, unsigned long addr, int * data)
 {
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-
- repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-
-	/* This is a hack for non-kernel-mapped video buffers and similar.  */
-	if (MAP_NR(page) < max_mapnr)
-		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-
-	/* We're bypassing pagetables, so we have to set the dirty bit
-	   ourselves.  This should also re-instate whatever read-only
-	   mode there was before.  */
-	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-	flush_tlb();
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int
-read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	DBG(DBG_MEM_ALL, ("in read_long\n"));
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > (PAGE_SIZE - sizeof(long))) {
-		struct vm_area_struct * vma_high = vma;
-		unsigned long low, align;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		align = addr & (sizeof(long) - 1);
-		addr -= align;
-		low = get_long(tsk, vma, addr);
-		if (align) {
-			unsigned long high;
-
-			high = get_long(tsk, vma_high, addr + sizeof(long));
-			low >>= align * 8;
-			low  |= high << (64 - align * 8);
-		}
-		*result = low;
-	} else {
-	        long l = get_long(tsk, vma, addr);
-
-		DBG(DBG_MEM_ALL, ("value is 0x%lx\n", l));
-		*result = l;
-	}
-	return 0;
+	int copied = access_process_vm(task, addr, data, sizeof(int), 0);
+	return (copied == sizeof(int)) ? 0 : -EIO;
 }
 
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int
-write_long(struct task_struct * tsk, unsigned long addr, unsigned long data)
+static inline int
+write_int(struct task_struct *task, unsigned long addr, int data)
 {
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low, high, align;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		align = addr & (sizeof(long) - 1);
-		addr -= align;
-		low  = get_long(tsk, vma, addr);
-		high = get_long(tsk, vma_high, addr + sizeof(long));
-		low  &= ~0UL >> (64 - align * 8);
-		high &= ~0UL << (align * 8);
-		low  |= data << (align * 8);
-		high |= data >> (64 - align * 8);
-		put_long(tsk, vma, addr, low);
-		put_long(tsk, vma_high, addr + sizeof(long), high);
-	} else
-		put_long(tsk, vma, addr, data);
-	return 0;
-}
-
-/*
- * Read a 32bit int from address space TSK.
- */
-static int
-read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data)
-{
-	unsigned long l, align;
-	int res;
-
-	align = addr & 0x7;
-	addr &= ~0x7;
-
-	res = read_long(tsk, addr, &l);
-	if (res < 0)
-		return res;
-
-	if (align == 0) {
-		*data = l;
-	} else {
-		*data = l >> 32;
-	}
-	return 0;
-}
-
-/*
- * Write a 32bit word to address space TSK.
- *
- * For simplicity, do a read-modify-write of the 64bit word that
- * contains the 32bit word that we are about to write.
- */
-static int
-write_int(struct task_struct * tsk, unsigned long addr, unsigned int data)
-{
-	unsigned long l, align;
-	int res;
-
-	align = addr & 0x7;
-	addr &= ~0x7;
-
-	res = read_long(tsk, addr, &l);
-	if (res < 0)
-		return res;
-
-	if (align == 0) {
-		l = (l & 0xffffffff00000000UL) | ((unsigned long) data <<  0);
-	} else {
-		l = (l & 0x00000000ffffffffUL) | ((unsigned long) data << 32);
-	}
-	return write_long(tsk, addr, l);
+	int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
+	return (copied == sizeof(int)) ? 0 : -EIO;
 }
 
 /*
@@ -521,16 +297,17 @@
 	switch (request) {
 	/* When I and D space are separate, these will need to be fixed.  */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */
-	case PTRACE_PEEKDATA:
-		down(&child->mm->mmap_sem);
-		ret = read_long(child, addr, &tmp);
-		up(&child->mm->mmap_sem);
-		DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
-		if (ret < 0)
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
 			goto out;
+		
 		regs.r0 = 0;	/* special return: no errors */
 		ret = tmp;
 		goto out;
+	}
 
 	/* Read register number ADDR. */
 	case PTRACE_PEEKUSR:
@@ -541,12 +318,12 @@
 
 	/* When I and D space are separate, this will have to be fixed.  */
 	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data));
-		down(&child->mm->mmap_sem);
-		ret = write_long(child, addr, data);
-		up(&child->mm->mmap_sem);
+	case PTRACE_POKEDATA: {
+		unsigned long tmp = data;
+		int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
+		ret = (copied == sizeof(tmp)) ? 0 : -EIO;
 		goto out;
+	}
 
 	case PTRACE_POKEUSR: /* write the specified register */
 		DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
diff -u --recursive --new-file v2.3.9/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.3.9/linux/arch/alpha/kernel/signal.c	Fri May 14 12:41:23 1999
+++ linux/arch/alpha/kernel/signal.c	Mon Jul  5 20:35:17 1999
@@ -16,7 +16,6 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/signal.h>
 #include <linux/stddef.h>
 
 #include <asm/bitops.h>
diff -u --recursive --new-file v2.3.9/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.3.9/linux/arch/alpha/kernel/smp.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/smp.c	Thu Jul  1 15:09:48 1999
@@ -603,7 +603,7 @@
 
 		update_one_process(current, 1, user, !user, cpu);
 	        if (current->pid) {
-	                if (--current->counter < 0) {
+	                if (--current->counter <= 0) {
 				current->counter = 0;
 	                        current->need_resched = 1;
 	                }
diff -u --recursive --new-file v2.3.9/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.3.9/linux/arch/arm/kernel/process.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/process.c	Mon Jul  5 20:35:17 1999
@@ -27,9 +27,7 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
-#include <linux/unistd.h>
 #include <linux/delay.h>
-#include <linux/smp.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 
diff -u --recursive --new-file v2.3.9/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c
--- v2.3.9/linux/arch/arm/kernel/time.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/time.c	Mon Jul  5 20:35:17 1999
@@ -23,8 +23,6 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.9/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c
--- v2.3.9/linux/arch/arm/nwfpe/fpmodule.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/fpmodule.c	Mon Jul  5 20:35:17 1999
@@ -36,7 +36,6 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/sched.h>
 #include <linux/init.h>
 
 #include <asm/system.h>
diff -u --recursive --new-file v2.3.9/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.9/linux/arch/i386/boot/setup.S	Sat Nov 28 17:18:54 1998
+++ linux/arch/i386/boot/setup.S	Mon Jul  5 20:04:47 1999
@@ -753,19 +753,29 @@
 ! This routine checks that the keyboard command queue is empty
 ! (after emptying the output buffers)
 !
-! No timeout is used - if this hangs there is something wrong with
-! the machine, and we probably couldn't proceed anyway.
+! Some machines have delusions that the keyboard buffer is always full
+! with no keyboard attached...
+
 empty_8042:
+       push    ecx
+       mov     ecx,#0xFFFFFF
+
+empty_8042_loop:
+       dec     ecx
+       jz      empty_8042_end_loop
+
 	call	delay
 	in	al,#0x64	! 8042 status port
 	test	al,#1		! output buffer?
 	jz	no_output
 	call	delay
 	in	al,#0x60	! read it
-	jmp	empty_8042
+	jmp	empty_8042_loop
 no_output:
 	test	al,#2		! is input buffer full?
-	jnz	empty_8042	! yes - loop
+	jnz	empty_8042_loop	! yes - loop
+empty_8042_end_loop:
+        pop     ecx
 	ret
 
 !
diff -u --recursive --new-file v2.3.9/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.9/linux/arch/i386/config.in	Wed Jun 30 13:38:18 1999
+++ linux/arch/i386/config.in	Thu Jul  1 14:22:56 1999
@@ -92,13 +92,7 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-  fi
-fi
+source drivers/misc/Config.in
 
 bool 'Advanced Power Management BIOS support' CONFIG_APM
 if [ "$CONFIG_APM" = "y" ]; then
diff -u --recursive --new-file v2.3.9/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.9/linux/arch/i386/defconfig	Wed Jun 30 13:38:18 1999
+++ linux/arch/i386/defconfig	Tue Jul  6 20:31:23 1999
@@ -70,11 +70,6 @@
 # CONFIG_I2O_PROC is not set
 
 #
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
@@ -98,7 +93,10 @@
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_BLK_DEV_PIIX=y
 # CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_CPQ_DA is not set
 
 #
 # Additional Block Devices
@@ -214,9 +212,17 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
 CONFIG_DUMMY=m
 # CONFIG_EQUALIZER is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -236,14 +242,22 @@
 # CONFIG_VIA_RHINE is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
-# CONFIG_DLCI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
 # CONFIG_TR is not set
+
+#
+# Wan interfaces
+#
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
-# CONFIG_RCPCI is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_DLCI is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.3.9/linux/arch/i386/kernel/irq.h	Tue Jun 22 14:43:14 1999
+++ linux/arch/i386/kernel/irq.h	Wed Jul  7 09:22:14 1999
@@ -238,7 +238,7 @@
  */
 static inline void x86_do_profile (unsigned long eip)
 {
-	if (prof_buffer && current->pid) {
+	if (prof_buffer) {
 		eip -= (unsigned long) &_stext;
 		eip >>= prof_shift;
 		/*
diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.3.9/linux/arch/i386/kernel/process.c	Fri Apr 30 08:13:37 1999
+++ linux/arch/i386/kernel/process.c	Mon Jul  5 20:35:17 1999
@@ -26,9 +26,7 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
-#include <linux/unistd.h>
 #include <linux/delay.h>
-#include <linux/smp.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.3.9/linux/arch/i386/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
+++ linux/arch/i386/kernel/ptrace.c	Sun Jul  4 13:41:08 1999
@@ -67,205 +67,6 @@
 	return 0;
 }
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk, 
-	struct vm_area_struct * vma, unsigned long addr)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
-	unsigned long data)
-{
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) < max_mapnr)
-		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-	flush_tlb();
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-		high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 1:
-				low >>= 8;
-				low |= high << 24;
-				break;
-			case 2:
-				low >>= 16;
-				low |= high << 16;
-				break;
-			case 3:
-				low >>= 24;
-				low |= high << 8;
-				break;
-		}
-		*result = low;
-	} else
-		*result = get_long(tsk, vma, addr);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-		high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 0: /* shouldn't happen, but safety first */
-				low = data;
-				break;
-			case 1:
-				low &= 0x000000ff;
-				low |= data << 8;
-				high &= ~0xff;
-				high |= data >> 24;
-				break;
-			case 2:
-				low &= 0x0000ffff;
-				low |= data << 16;
-				high &= ~0xffff;
-				high |= data >> 16;
-				break;
-			case 3:
-				low &= 0x00ffffff;
-				low |= data << 24;
-				high &= ~0xffffff;
-				high |= data >> 8;
-				break;
-		}
-		put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
-		put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
-	} else
-		put_long(tsk, vma, addr, data);
-	return 0;
-}
-
 static int putreg(struct task_struct *child,
 	unsigned long regno, unsigned long value)
 {
@@ -402,12 +203,13 @@
 		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
+			int copied;
 
-			down(&child->mm->mmap_sem);
-			ret = read_long(child, addr, &tmp);
-			up(&child->mm->mmap_sem);
-			if (ret >= 0)
-				ret = put_user(tmp,(unsigned long *) data);
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
+				goto out;
+			ret = put_user(tmp,(unsigned long *) data);
 			goto out;
 		}
 
@@ -436,9 +238,10 @@
       /* when I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			down(&child->mm->mmap_sem);
-			ret = write_long(child,addr,data);
-			up(&child->mm->mmap_sem);
+			ret = 0;
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				goto out;
+			ret = -EIO;
 			goto out;
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.9/linux/arch/i386/kernel/setup.c	Tue Jun  8 10:42:46 1999
+++ linux/arch/i386/kernel/setup.c	Mon Jul  5 20:04:47 1999
@@ -11,7 +11,7 @@
  *      Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
  * 
  *  Force Centaur C6 processors to report MTRR capability.
- *      Bart Hartgers <bart@etpmod.phys.tue.nl>, May 199.
+ *      Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999.
  *
  *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
  */
@@ -690,8 +690,8 @@
 	    NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_INTEL,	6,
 	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
-            NULL, "Pentium II (Deschutes)", "Mobile Pentium II", NULL,
-	    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)",
+	    "Pentium III (Coppermine)", NULL, NULL, NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_AMD,	4,
 	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
 	    "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -799,16 +799,15 @@
 			/* Names for the Pentium II Celeron processors 
                            detectable only by also checking the cache size */
 			if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
-			    && (cpu_models[i].x86 == 6)){ 
-				if(c->x86_model == 6 && c->x86_cache_size == 128) {
+			    && (cpu_models[i].x86 == 6))
+			{
+			 	if(c->x86_model == 5 &&  c->x86_cache_size == 0)
+					p = "Celeron (Covington)";						
+				else if(c->x86_model == 6 && c->x86_cache_size == 128)
                             		p = "Celeron (Mendocino)"; 
-                          	}
-			  	else { 
-                            	if (c->x86_model == 5 && c->x86_cache_size == 0) {
-				  	p = "Celeron (Covington)";
-			    	}
-                        }
-                    }
+ 			  	else if(c->x86_model == 5 && c->x86_cache_size == 256)
+					p = "Celeron (Dixon)";
+			}
 		}
 			
 	}
diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.9/linux/arch/i386/kernel/smp.c	Wed Jun 16 19:26:27 1999
+++ linux/arch/i386/kernel/smp.c	Thu Jul  1 15:09:00 1999
@@ -1792,7 +1792,7 @@
 		update_one_process(p, 1, user, system, cpu);
 		if (p->pid) {
 			p->counter -= 1;
-			if (p->counter < 0) {
+			if (p->counter <= 0) {
 				p->counter = 0;
 				p->need_resched = 1;
 			}
diff -u --recursive --new-file v2.3.9/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h
--- v2.3.9/linux/arch/i386/math-emu/fpu_emu.h	Sun Sep 13 12:58:05 1998
+++ linux/arch/i386/math-emu/fpu_emu.h	Mon Jul  5 20:35:17 1999
@@ -165,8 +165,6 @@
 #define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
 #define signnegative(a) (signbyte(a) & 0x80)
 
-#include "fpu_proto.h"
-
 static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
 {
   *(short *)&(y->exp) = *(const short *)&(x->exp); 
diff -u --recursive --new-file v2.3.9/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.9/linux/arch/i386/mm/fault.c	Tue May 11 17:11:34 1999
+++ linux/arch/i386/mm/fault.c	Sat Jul  3 12:04:12 1999
@@ -50,7 +50,8 @@
 	start &= PAGE_MASK;
 
 	for (;;) {
-		handle_mm_fault(current,vma, start, 1);
+		if (handle_mm_fault(current, vma, start, 1) <= 0)
+			goto bad_area;
 		if (!size)
 			break;
 		size--;
@@ -162,8 +163,13 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	if (!handle_mm_fault(tsk, vma, address, write))
-		goto do_sigbus;
+	{
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (fault < 0)
+			goto out_of_memory;
+		if (!fault)
+			goto do_sigbus;
+	}
 
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
@@ -255,6 +261,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", tsk->comm);
+	if (error_code & 4)
+		do_exit(SIGKILL);
+	goto no_context;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 
diff -u --recursive --new-file v2.3.9/linux/arch/mips/boot/elf2ecoff.c linux/arch/mips/boot/elf2ecoff.c
--- v2.3.9/linux/arch/mips/boot/elf2ecoff.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/boot/elf2ecoff.c	Mon Jul  5 20:35:17 1999
@@ -35,7 +35,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <fcntl.h>
diff -u --recursive --new-file v2.3.9/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.3.9/linux/arch/mips/config.in	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/config.in	Mon Jul  5 19:44:57 1999
@@ -93,7 +93,7 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-  tristate 'Parallel port support' CONFIG_PARPORT
+source drivers/misc/Config.in
 fi
 endmenu
 
diff -u --recursive --new-file v2.3.9/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.3.9/linux/arch/mips/defconfig	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/defconfig	Mon Jul  5 19:44:57 1999
@@ -63,11 +63,6 @@
 # CONFIG_I2O_PROC is not set
 
 #
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
 # Block devices
 #
 CONFIG_BLK_DEV_FD=m
diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c
--- v2.3.9/linux/arch/mips/kernel/irixioctl.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/irixioctl.c	Tue Jul  6 10:11:40 1999
@@ -29,20 +29,21 @@
 				unsigned long arg);
 extern asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count);
 extern void start_tty(struct tty_struct *tty);
-
 static struct tty_struct *get_tty(int fd)
 {
 	struct file *filp;
+	struct tty_struct *ttyp = NULL;
 
-	if(!(filp = fcheck(fd)))
-		return ((struct tty_struct *) 0);
-	if(filp->private_data) {
-		struct tty_struct *ttyp = (struct tty_struct *) filp->private_data;
+	read_lock(&current->files->file_lock);
+	filp = fcheck(fd);
+	if(filp && filp->private_data) {
+		ttyp = (struct tty_struct *) filp->private_data;
 
-		if(ttyp->magic == TTY_MAGIC)
-			return ttyp;
+		if(ttyp->magic != TTY_MAGIC)
+			ttyp =NULL;
 	}
-	return ((struct tty_struct *) 0);
+	read_unlock(&current->files->file_lock);
+	return ttyp;
 }
 
 static struct tty_struct *get_real_tty(struct tty_struct *tp)
diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.3.9/linux/arch/mips/kernel/ptrace.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/ptrace.c	Mon Jul  5 19:44:57 1999
@@ -25,218 +25,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
-			      struct vm_area_struct * vma, unsigned long addr)
-{
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page, retval;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	/* This is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= MAP_NR(high_memory))
-		return 0;
-	page += addr & ~PAGE_MASK;
-	/* We can't use flush_page_to_ram() since we're running in
-	 * another context ...
-	 */
-	flush_cache_all();
-	retval = *(unsigned long *) page;
-	flush_cache_all();	/* VCED avoidance  */
-	return retval;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct *tsk,
-		     struct vm_area_struct * vma, unsigned long addr,
-	unsigned long data)
-{
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	/* This is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) < MAP_NR(high_memory))
-		flush_cache_all();
-	*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-	if (MAP_NR(page) < MAP_NR(high_memory))
-		flush_cache_all();
-	/*
-	 * We're bypassing pagetables, so we have to set the dirty bit
-	 * ourselves this should also re-instate whatever read-only mode
-	 * there was before
-	 */
-	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-	flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-		high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 1:
-				low >>= 8;
-				low |= high << 24;
-				break;
-			case 2:
-				low >>= 16;
-				low |= high << 16;
-				break;
-			case 3:
-				low >>= 24;
-				low |= high << 8;
-				break;
-		}
-		*result = low;
-	} else
-		*result = get_long(tsk, vma, addr);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-		high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 0: /* shouldn't happen, but safety first */
-				low = data;
-				break;
-			case 1:
-				low &= 0x000000ff;
-				low |= data << 8;
-				high &= ~0xff;
-				high |= data >> 24;
-				break;
-			case 2:
-				low &= 0x0000ffff;
-				low |= data << 16;
-				high &= ~0xffff;
-				high |= data >> 16;
-				break;
-			case 3:
-				low &= 0x00ffffff;
-				low |= data << 24;
-				high &= ~0xffffff;
-				high |= data >> 8;
-				break;
-		}
-		put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
-		put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
-	} else
-		put_long(tsk, vma, addr, data);
-	return 0;
-}
-
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
@@ -322,15 +110,16 @@
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: {
 		unsigned long tmp;
+		int copied;
 
-		down(&child->mm->mmap_sem);
-		res = read_long(child, addr, &tmp);
-		up(&child->mm->mmap_sem);
-		if (res < 0)
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		res = -EIO;
+		if (copied != sizeof(tmp))
 			goto out;
 		res = put_user(tmp,(unsigned long *) data);
+
 		goto out;
-		}
+	}
 
 	/* Read the word at location addr in the USER area.  */
 	case PTRACE_PEEKUSR: {
@@ -394,9 +183,11 @@
 
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
-		down(&child->mm->mmap_sem);
-		res = write_long(child,addr,data);
-		up(&child->mm->mmap_sem);
+		res = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+		    == sizeof(data))
+			goto out;
+		res = -EIO;
 		goto out;
 
 	case PTRACE_POKEUSR: {
diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S
--- v2.3.9/linux/arch/mips/kernel/r4k_misc.S	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/r4k_misc.S	Mon Jul  5 20:35:17 1999
@@ -13,7 +13,6 @@
 #include <asm/offset.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
-#include <asm/current.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsconfig.h>
 #include <asm/mipsregs.h>
diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c
--- v2.3.9/linux/arch/mips/kernel/setup.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/setup.c	Mon Jul  5 20:35:17 1999
@@ -30,7 +30,6 @@
 #endif
 #include <linux/ide.h>
 #ifdef CONFIG_RTC
-#include <linux/ioport.h>
 #include <linux/timex.h>
 #endif
 
diff -u --recursive --new-file v2.3.9/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.3.9/linux/arch/mips/mm/fault.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/mips/mm/fault.c	Mon Jul  5 19:44:57 1999
@@ -43,7 +43,7 @@
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
 			      unsigned long address)
 {
 	struct vm_area_struct * vma;
@@ -59,7 +59,7 @@
 		goto no_context;
 #if 0
 	printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid,
-	       address, writeaccess, regs->cp0_epc);
+	       address, write, regs->cp0_epc);
 #endif
 	down(&mm->mmap_sem);
 	vma = find_vma(mm, address);
@@ -76,14 +76,26 @@
  * we can handle it..
  */
 good_area:
-	if (writeaccess) {
+	if (write) {
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	} else {
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	handle_mm_fault(tsk, vma, address, writeaccess);
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+	{
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (fault < 0)
+			goto out_of_memory;
+		if (!fault)
+			goto do_sigbus;
+	}
 	up(&mm->mmap_sem);
 	return;
 
@@ -96,12 +108,12 @@
 
 	if (user_mode(regs)) {
 		tsk->tss.cp0_badvaddr = address;
-		tsk->tss.error_code = writeaccess;
+		tsk->tss.error_code = write;
 #if 0
 		printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n"
 		       "%08lx (epc == %08lx, ra == %08lx)\n",
 		       tsk->comm,
-		       writeaccess ? "writeaccess to" : "readaccess from",
+		       write ? "write access to" : "read access from",
 		       address,
 		       (unsigned long) regs->cp0_epc,
 		       (unsigned long) regs->regs[31]);
@@ -132,6 +144,31 @@
 	printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
 	       "address %08lx, epc == %08lx, ra == %08lx\n",
 	       address, regs->cp0_epc, regs->regs[31]);
-	die("Oops", regs, writeaccess);
+	die("Oops", regs, write);
 	do_exit(SIGKILL);
+
+/*
+ * 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", tsk->comm);
+	if (user_mode(regs))
+		do_exit(SIGKILL);
+	goto no_context;
+
+do_sigbus:
+	up(&mm->mmap_sem);
+
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 * XXX Store details about fault for siginfo handling into tss.
+	 */
+	force_sig(SIGBUS, tsk);
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!user_mode(regs))
+		goto no_context;
 }
diff -u --recursive --new-file v2.3.9/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c
--- v2.3.9/linux/arch/mips/sgi/kernel/indy_sc.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/mips/sgi/kernel/indy_sc.c	Thu Jul  1 10:45:57 1999
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/autoconf.h>
 
 #include <asm/bcache.h>
 #include <asm/sgi.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c
--- v2.3.9/linux/arch/ppc/amiga/amiints.c	Thu Jan  7 08:46:58 1999
+++ linux/arch/ppc/amiga/amiints.c	Mon Jul  5 20:07:02 1999
@@ -108,7 +108,7 @@
 	custom.intreq = 0x7fff;
 
 #ifdef CONFIG_APUS
-	/* Clear any inter-CPU interupt requests. Circumvents bug in
+	/* Clear any inter-CPU interrupt requests. Circumvents bug in
            Blizzard IPL emulation HW (or so it appears). */
 	APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
 
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c
--- v2.3.9/linux/arch/ppc/amiga/config.c	Mon Dec 21 08:37:20 1998
+++ linux/arch/ppc/amiga/config.c	Mon Jul  5 20:35:17 1999
@@ -30,7 +30,6 @@
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
-#include <linux/init.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.9/linux/arch/ppc/config.in	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/config.in	Thu Jul  1 14:22:56 1999
@@ -66,13 +66,7 @@
 define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-  fi
-fi
+source drivers/misc/Config.in
 
 bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.9/linux/arch/ppc/kernel/irq.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/irq.c	Mon Jul  5 20:35:17 1999
@@ -50,7 +50,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/gg2.h>
 #include <asm/cache.h>
 #include <asm/prom.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.9/linux/arch/ppc/kernel/pci.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/pci.c	Mon Jul  5 20:35:17 1999
@@ -9,7 +9,6 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/config.h>
-#include <linux/pci.h>
 #include <linux/openpic.h>
 
 #include <asm/processor.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c
--- v2.3.9/linux/arch/ppc/kernel/ppc-stub.c	Tue Aug  4 16:06:36 1998
+++ linux/arch/ppc/kernel/ppc-stub.c	Mon Jul  5 20:35:17 1999
@@ -107,7 +107,6 @@
 
 #include <asm/system.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/kgdb.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.3.9/linux/arch/ppc/kernel/prep_setup.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Jul  5 20:35:17 1999
@@ -40,7 +40,6 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.9/linux/arch/ppc/kernel/process.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/process.c	Thu Jul  1 10:45:57 1999
@@ -31,7 +31,6 @@
 #include <linux/malloc.h>
 #include <linux/user.h>
 #include <linux/elf.h>
-#include <linux/elf.h>
 #include <linux/init.h>
 
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.9/linux/arch/ppc/kernel/setup.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/setup.c	Mon Jul  5 20:35:17 1999
@@ -32,7 +32,6 @@
 #endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
-#include <asm/ide.h>
 
 extern void pmac_init(unsigned long r3,
                       unsigned long r4,
diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.9/linux/arch/ppc/kernel/smp.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/smp.c	Thu Jul  1 15:09:00 1999
@@ -85,7 +85,7 @@
 			update_one_process(p, 1, user, system, cpu);
 
 			p->counter -= 1;
-			if (p->counter < 0) {
+			if (p->counter <= 0) {
 				p->counter = 0;
 				current->need_resched = 1;
 			}
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c
--- v2.3.9/linux/arch/sparc/ap1000/aplib.c	Tue Aug  4 16:03:34 1998
+++ linux/arch/sparc/ap1000/aplib.c	Mon Jul  5 20:35:17 1999
@@ -27,7 +27,6 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/segment.h>
 #include <asm/uaccess.h>
 
  #include <asm/ap1000/pgtapmmu.h>
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- v2.3.9/linux/arch/sparc/kernel/pcic.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc/kernel/pcic.c	Mon Jul  5 20:35:17 1999
@@ -20,7 +20,6 @@
 #include <asm/ebus.h>
 #include <asm/sbus.h> /* for sanity check... */
 #include <asm/swift.h> /* for cache flushing. */
-
 #include <asm/io.h>
 
 #undef PROM_DEBUG
@@ -39,7 +38,6 @@
 #include <linux/timex.h>
 #include <linux/interrupt.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/oplib.h>
 #include <asm/pcic.h>
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.3.9/linux/arch/sparc/kernel/process.c	Tue May 11 08:24:31 1999
+++ linux/arch/sparc/kernel/process.c	Mon Jul  5 20:35:17 1999
@@ -37,7 +37,6 @@
 #include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/psr.h>
-#include <asm/system.h>
 #include <asm/elf.h>
 
 extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.3.9/linux/arch/sparc/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
+++ linux/arch/sparc/kernel/ptrace.c	Mon Jul  5 11:30:11 1999
@@ -24,202 +24,6 @@
 
 #define MAGIC_CONSTANT 0x80000000
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
-	struct vm_area_struct * vma, unsigned long addr)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-	unsigned long page, retval;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	retval = *(unsigned long *) page;
-	flush_page_to_ram(page);
-	return retval;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
-	unsigned long addr, unsigned long data)
-{
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	flush_cache_page(vma, addr);
-	if (MAP_NR(page) < max_mapnr) {
-		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-		flush_page_to_ram(page);
-	}
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-	flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-		     unsigned long * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	*result = get_long(tsk, vma, addr);
-	return 0;
-}
-
-static int read_byte(struct task_struct *tsk, unsigned long addr,
-		     unsigned char *result)
-{
-	struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3);
-	unsigned long tmp;
-
-	if(!vma)
-		return -EIO;
-	tmp = get_long(tsk, vma, (addr & ~3));
-	switch(addr & 3) {
-	case 0:
-		*result = (tmp & 0xff000000)>>24;
-		break;
-	case 1:
-		*result = (tmp & 0x00ff0000)>>16;
-		break;
-	case 2:
-		*result = (tmp & 0x0000ff00)>>8;
-		break;
-	case 3:
-		*result = (tmp & 0x000000ff);
-		break;
-	}
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-		      unsigned long data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	put_long(tsk, vma, addr, data);
-	return 0;
-}
-
-static int write_byte(struct task_struct * tsk, unsigned long addr,
-		      unsigned char data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3));
-	unsigned long tmp;
-
-	if (!vma)
-		return -EIO;
-	tmp = get_long(tsk, vma, (addr & ~3));
-	switch(addr & 3) {
-	case 0:
-		tmp &= 0x00ffffff;
-		tmp |= (data << 24);
-		break;
-	case 1:
-		tmp &= 0xff00ffff;
-		tmp |= ((data << 16) & 0x00ff0000);
-		break;
-	case 2:
-		tmp &= 0xffff00ff;
-		tmp |= ((data << 8) & 0x0000ff00);
-		break;
-	case 3:
-		tmp &= 0xffffff00;
-		tmp |= (data & 0x000000ff);
-		break;
-	}
-	put_long(tsk, vma, (addr & ~3), tmp);
-	return 0;
-}
 
 /* Returning from ptrace is a bit tricky because the syscall return
  * low level code assumes any value returned which is negative and
@@ -565,24 +369,12 @@
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: {
 		unsigned long tmp;
-		int res;
-
-		/* XXX Find out what is really going on. */
-		flush_cache_all();
 
-		/* Non-word alignment _not_ allowed on Sparc. */
-		if(addr & (sizeof(unsigned long) - 1)) {
-			pt_error_return(regs, EINVAL);
-			goto out;
-		}
-		down(&child->mm->mmap_sem);
-		res = read_long(child, addr, &tmp);
-		up(&child->mm->mmap_sem);
-		if (res < 0) {
-			pt_error_return(regs, -res);
-			goto out;
-		}
-		pt_os_succ_return(regs, tmp, (long *) data);
+		if (access_process_vm(child, addr,
+				      &tmp, sizeof(tmp), 0) == sizeof(tmp))
+			pt_os_succ_return(regs, tmp, (long *)data);
+		else
+			pt_error_return(regs, EIO);
 		goto out;
 	}
 
@@ -596,22 +388,11 @@
 
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA: {
-		struct vm_area_struct *vma;
-		int res;
-
-		/* Non-word alignment _not_ allowed on Sparc. */
-		if(addr & (sizeof(unsigned long) - 1)) {
-			pt_error_return(regs, EINVAL);
-			goto out;
-		}
-		down(&child->mm->mmap_sem);
-		vma = find_extend_vma(child, addr);
-		res = write_long(child, addr, data);
-		up(&child->mm->mmap_sem);
-		if(res < 0)
-			pt_error_return(regs, -res);
+		if (access_process_vm(child, addr,
+				      &data, sizeof(data), 1) == sizeof(data))
+			pt_succ_return(regs, 0);
 		else
-			pt_succ_return(regs, res);
+			pt_error_return(regs, EIO);
 		goto out;
 	}
 
@@ -737,56 +518,31 @@
 
 	case PTRACE_READTEXT:
 	case PTRACE_READDATA: {
-		unsigned char *dest = (unsigned char *) addr2;
-		unsigned long src = addr;
-		unsigned char tmp;
-		int res, len = data;
-
-		res = verify_area(VERIFY_WRITE, dest, len);
-		if(res) {
-			pt_error_return(regs, -res);
-			goto out;
-		}
-		while(len) {
-			down(&child->mm->mmap_sem);
-			res = read_byte(child, src, &tmp);
-			up(&child->mm->mmap_sem);
-			if(res < 0) {
-				pt_error_return(regs, -res);
-				goto out;
-			}
-			__put_user(tmp, dest);
-			src++; dest++; len--;
+		int res = ptrace_readdata(child, addr, (void *) addr2, data);
+
+		if (res == data) {
+			pt_succ_return(regs, 0);
+			goto out;
 		}
-		pt_succ_return(regs, 0);
+		/* Partial read is an IO failure */
+		if (res >= 0)
+			res = -EIO;
+		pt_error_return(regs, -res);
 		goto out;
 	}
 
 	case PTRACE_WRITETEXT:
 	case PTRACE_WRITEDATA: {
-		unsigned char *src = (unsigned char *) addr2;
-		unsigned long dest = addr;
-		int res, len = data;
-
-		res = verify_area(VERIFY_READ, src, len);
-		if(res) {
-			pt_error_return(regs, -res);
-			goto out;
-		}
-		while(len) {
-			unsigned long tmp;
-
-			__get_user(tmp, src);
-			down(&child->mm->mmap_sem);
-			res = write_byte(child, dest, tmp);
-			up(&child->mm->mmap_sem);
-			if(res < 0) {
-				pt_error_return(regs, -res);
-				goto out;
-			}
-			src++; dest++; len--;
+		int res = ptrace_writedata(child, (void *) addr2, addr, data);
+
+		if (res == data) {
+			pt_succ_return(regs, 0);
+			goto out;
 		}
-		pt_succ_return(regs, 0);
+		/* Partial write is an IO failure */
+		if (res >= 0)
+			res = -EIO;
+		pt_error_return(regs, -res);
 		goto out;
 	}
 
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c
--- v2.3.9/linux/arch/sparc/kernel/sparc-stub.c	Tue Apr 14 17:44:19 1998
+++ linux/arch/sparc/kernel/sparc-stub.c	Mon Jul  5 20:35:17 1999
@@ -105,7 +105,6 @@
 #include <asm/oplib.h>
 #include <asm/head.h>
 #include <asm/traps.h>
-#include <asm/system.h>
 #include <asm/vac-ops.h>
 #include <asm/kgdb.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.9/linux/arch/sparc/kernel/sparc_ksyms.c	Sun Mar 21 07:23:38 1999
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Mon Jul  5 20:35:17 1999
@@ -40,7 +40,6 @@
 #include <asm/dma.h>
 #endif
 #include <asm/a.out.h>
-#include <asm/spinlock.h>
 #include <asm/io-unit.h>
 
 struct poll {
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.3.9/linux/arch/sparc/kernel/sun4d_smp.c	Tue May 11 08:24:31 1999
+++ linux/arch/sparc/kernel/sun4d_smp.c	Thu Jul  1 15:09:00 1999
@@ -473,7 +473,7 @@
 		if(current->pid) {
 			update_one_process(current, 1, user, !user, cpu);
 
-			if(--current->counter < 0) {
+			if(--current->counter <= 0) {
 				current->counter = 0;
 				current->need_resched = 1;
 			}
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.3.9/linux/arch/sparc/kernel/sun4m_smp.c	Tue May 11 08:24:31 1999
+++ linux/arch/sparc/kernel/sun4m_smp.c	Thu Jul  1 15:09:01 1999
@@ -454,7 +454,7 @@
 		if(current->pid) {
 			update_one_process(current, 1, user, !user, cpu);
 
-			if(--current->counter < 0) {
+			if(--current->counter <= 0) {
 				current->counter = 0;
 				current->need_resched = 1;
 			}
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c
--- v2.3.9/linux/arch/sparc/kernel/sunos_ioctl.c	Tue Oct 27 09:52:20 1998
+++ linux/arch/sparc/kernel/sunos_ioctl.c	Tue Jul  6 10:11:40 1999
@@ -36,11 +36,10 @@
 
 asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
 {
-	struct file *filp;
 	int ret = -EBADF;
 
 	lock_kernel();
-	if (fd >= SUNOS_NR_OPEN || !(filp = current->files->fd [fd]))
+	if (fd >= SUNOS_NR_OPEN || !fcheck(fd))
 		goto out;
 
 	/* First handle an easy compat. case for tty ldisc. */
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.9/linux/arch/sparc/kernel/sys_sunos.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Jul  5 20:35:17 1999
@@ -26,7 +26,6 @@
 #include <linux/signal.h>
 #include <linux/uio.h>
 #include <linux/utsname.h>
-#include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c
--- v2.3.9/linux/arch/sparc/mm/asyncd.c	Wed May 12 08:41:12 1999
+++ linux/arch/sparc/mm/asyncd.c	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.13 1999/05/12 11:11:34 davem Exp $
+/*  $Id: asyncd.c,v 1.15 1999/07/04 04:35:50 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.3.9/linux/arch/sparc/mm/fault.c	Wed Mar 10 16:53:36 1999
+++ linux/arch/sparc/mm/fault.c	Mon Jul  5 20:35:18 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $
+/* $Id: fault.c,v 1.103 1999/07/04 04:35:51 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -14,7 +14,6 @@
 #include <linux/mman.h>
 #include <linux/tasks.h>
 #include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.9/linux/arch/sparc/mm/srmmu.c	Wed Apr 28 10:58:10 1999
+++ linux/arch/sparc/mm/srmmu.c	Mon Jul  5 11:44:55 1999
@@ -2076,6 +2076,7 @@
 			goto done;
 		inode = file->f_dentry->d_inode;
 		offset = (address & PAGE_MASK) - vma->vm_start;
+		spin_lock(&inode->i_shared_lock);
 		vmaring = inode->i_mmap; 
 		do {
 			/* Do not mistake ourselves as another mapping. */
@@ -2109,6 +2110,7 @@
 				}
 			}
 		} while ((vmaring = vmaring->vm_next_share) != NULL);
+		spin_unlock(&inode->i_shared_lock);
 
 		if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
 			pgdp = srmmu_pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.9/linux/arch/sparc/mm/sun4c.c	Wed Mar 10 16:53:36 1999
+++ linux/arch/sparc/mm/sun4c.c	Mon Jul  5 11:44:55 1999
@@ -2682,8 +2682,10 @@
 		inode = dentry->d_inode;
 	if(inode) {
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
-		struct vm_area_struct *vmaring = inode->i_mmap; 
+		struct vm_area_struct *vmaring;
 		int alias_found = 0;
+		spin_lock(&inode->i_shared_lock);
+		vmaring = inode->i_mmap; 
 		do {
 			unsigned long vaddr = vmaring->vm_start + offset;
 			unsigned long start;
@@ -2712,6 +2714,7 @@
 				}
 			}
 		} while ((vmaring = vmaring->vm_next_share) != NULL);
+		spin_unlock(&inode->i_shared_lock);
 
 		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = sun4c_pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.9/linux/arch/sparc64/config.in	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/config.in	Tue Jul  6 19:05:48 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.66 1999/03/29 05:08:42 davem Exp $
+# $Id: config.in,v 1.67 1999/05/01 09:17:37 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -68,20 +68,8 @@
 fi
 
 if [ "$CONFIG_PCI" = "y" ]; then
-  tristate 'Parallel port support' CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT" != "n" ]; then
-    dep_tristate '  Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT
-    if [ "$CONFIG_PARPORT_AX" = "m" ]; then
-      define_bool CONFIG_PARPORT_LOWLEVEL_MODULE y
-    fi
-    if [ "$CONFIG_PARPORT_AX" != "n" ]; then
-      bool '  Support foreign hardware' CONFIG_PARPORT_OTHER
-    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
+  source drivers/misc/Config.in
+  dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
 fi
 endmenu
@@ -232,6 +220,16 @@
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
 	int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Video For Linux'
+tristate 'Video For Linux' CONFIG_VIDEO_DEV
+if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
+  if [ "$CONFIG_PCI" != "n" ]; then
+    dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
+  fi
 fi
 endmenu
 
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.9/linux/arch/sparc64/defconfig	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/defconfig	Tue Jul  6 19:05:48 1999
@@ -93,11 +93,13 @@
 CONFIG_BINFMT_MISC=m
 CONFIG_SOLARIS_EMUL=m
 CONFIG_PARPORT=m
-CONFIG_PARPORT_AX=m
-CONFIG_PARPORT_LOWLEVEL_MODULE=y
+# CONFIG_PARPORT_PC is not set
+# 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_PRINTER=m
-CONFIG_PRINTER_READBACK=y
 CONFIG_ENVCTRL=m
 
 #
@@ -260,6 +262,12 @@
 #
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_BT848=y
 
 #
 # Filesystems
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.3.9/linux/arch/sparc64/kernel/binfmt_aout32.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Thu Jul  1 17:33:12 1999
@@ -311,9 +311,10 @@
 		fd = open_dentry(bprm->dentry, O_RDONLY);
 		if (fd < 0)
 			return fd;
-		file = fcheck(fd);
+		file = fget(fd);
 
 		if (!file->f_op || !file->f_op->mmap) {
+			fput(fd);
 			sys_close(fd);
 			do_brk(0, ex.a_text+ex.a_data);
 			read_exec(bprm->dentry, fd_offset,
@@ -327,6 +328,7 @@
 			fd_offset);
 
 		if (error != N_TXTADDR(ex)) {
+			fput(file);
 			sys_close(fd);
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -336,6 +338,7 @@
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
+		fput(file);
 		sys_close(fd);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.9/linux/arch/sparc64/kernel/ioctl32.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/kernel/ioctl32.c	Tue Jul  6 10:11:40 1999
@@ -1696,9 +1696,9 @@
 	int error = -EBADF;
 
 	lock_kernel();
-	filp = fcheck(fd);
+	filp = fget(fd);
 	if(!filp)
-		goto out;
+		goto out2;
 
 	if (!filp->f_op || !filp->f_op->ioctl) {
 		error = sys_ioctl (fd, cmd, arg);
@@ -2381,6 +2381,8 @@
 		break;
 	}
 out:
+	fput(filp);
+out2:
 	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
--- v2.3.9/linux/arch/sparc64/kernel/psycho.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/kernel/psycho.c	Mon Jul  5 20:35:18 1999
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.85 1999/04/02 14:54:28 davem Exp $
+/* $Id: psycho.c,v 1.86 1999/07/01 10:39:43 davem Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -68,7 +68,6 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 
-#include <asm/io.h>
 #include <asm/oplib.h>
 #include <asm/pbm.h>
 #include <asm/apb.h>
@@ -757,13 +756,15 @@
 	unsigned short stmp;
 	unsigned int itmp;
 
+#if 0
 	for(pdev = pci_devices; pdev; pdev = pdev->next) {
 		if(pdev->vendor == PCI_VENDOR_ID_SUN &&
 		   pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
-			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
+			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
 			break;
 		}
 	}
+#endif
 	for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
 		if (pdev->vendor == PCI_VENDOR_ID_SUN &&
 		    pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
@@ -795,13 +796,14 @@
 			pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
 			itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
 			pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
-
+#if 0
 			/* Don't mess with the retry limit and PIO/DMA latency
 			 * timer settings.  But do set primary and secondary
 			 * latency timers.
 			 */
-			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
-			pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 128);
+			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+			pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
+#endif
 		}
 	}
 }
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.3.9/linux/arch/sparc64/kernel/ptrace.c	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc64/kernel/ptrace.c	Mon Jul  5 11:30:11 1999
@@ -28,242 +28,6 @@
 
 #define MAGIC_CONSTANT 0x80000000
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static pte_t *ptrace_get_page(struct task_struct * tsk,
-	struct vm_area_struct * vma, unsigned long addr, int write)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-
-	/* Seems non-intuitive but the page copy/clear routines always
-	 * check current's value.
-	 */
-	current->mm->segments = (void *) (addr & PAGE_SIZE);
-
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %016lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %016lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
-	}
-	if (write && !pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
-	}
-	return pgtable;
-}
-
-/* We must bypass the L1-cache to avoid alias issues.  -DaveM */
-static __inline__ unsigned long read_user_long(unsigned long kvaddr)
-{
-	unsigned long ret;
-
-	__asm__ __volatile__("ldxa [%1] %2, %0"
-			     : "=r" (ret)
-			     : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-	return ret;
-}
-
-static __inline__ unsigned int read_user_int(unsigned long kvaddr)
-{
-	unsigned int ret;
-
-	__asm__ __volatile__("lduwa [%1] %2, %0"
-			     : "=r" (ret)
-			     : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-	return ret;
-}
-
-static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val)
-{
-	__asm__ __volatile__("stxa %0, [%1] %2"
-			     : /* no outputs */
-			     : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-}
-
-static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val)
-{
-	__asm__ __volatile__("stwa %0, [%1] %2"
-			     : /* no outputs */
-			     : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
-}
-
-static inline unsigned long get_long(struct task_struct * tsk,
-	struct vm_area_struct * vma, unsigned long addr)
-{
-	pte_t * pgtable;
-	unsigned long page, retval;
-	
-	if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0;
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	retval = read_user_long(page);
-	flush_page_to_ram(page);
-	return retval;
-}
-
-static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
-	unsigned long addr, unsigned long data)
-{
-	pte_t *pgtable;
-	unsigned long page;
-
-	if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return;
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	flush_cache_page(vma, addr);
-	if (MAP_NR(page) < max_mapnr) {
-		unsigned long pgaddr;
-
-		pgaddr = page + (addr & ~PAGE_MASK);
-		write_user_long(pgaddr, data);
-
-		__asm__ __volatile__("
-		membar	#StoreStore
-		flush	%0
-"		: : "r" (pgaddr & ~7) : "memory");
-	}
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-	flush_tlb_page(vma, addr);
-}
-
-static inline unsigned int get_int(struct task_struct * tsk,
-	struct vm_area_struct * vma, unsigned long addr)
-{
-	pte_t * pgtable;
-	unsigned long page;
-	unsigned int retval;
-	
-	if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0;
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	retval = read_user_int(page);
-	flush_page_to_ram(page);
-	return retval;
-}
-
-static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma,
-	unsigned long addr, unsigned int data)
-{
-	pte_t *pgtable;
-	unsigned long page;
-
-	if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return;
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	flush_cache_page(vma, addr);
-	if (MAP_NR(page) < max_mapnr) {
-		unsigned long pgaddr;
-
-		pgaddr = page + (addr & ~PAGE_MASK);
-		write_user_int(pgaddr, data);
-
-		__asm__ __volatile__("
-		membar	#StoreStore
-		flush	%0
-"		: : "r" (pgaddr & ~7) : "memory");
-	}
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-	flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-		     unsigned long * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	*result = get_long(tsk, vma, addr);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_int() to read a int.
- */
-static int read_int(struct task_struct * tsk, unsigned long addr,
-		     unsigned int * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	*result = get_int(tsk, vma, addr);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-		      unsigned long data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	put_long(tsk, vma, addr, data);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_int() to write a int.
- */
-static int write_int(struct task_struct * tsk, unsigned long addr,
-		     unsigned int data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	put_int(tsk, vma, addr, data);
-	return 0;
-}
-
 /* Returning from ptrace is a bit tricky because the syscall return
  * low level code assumes any value returned which is negative and
  * is a valid errno will mean setting the condition codes to indicate
@@ -310,175 +74,6 @@
 		pt_succ_return_linux (regs, val, addr);
 }
 
-#if 0
-/* XXX: Implement this some day */
-/* Fuck me gently with a chainsaw... */
-static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
-				   struct task_struct *tsk, long *addr)
-{
-	struct pt_regs *cregs = tsk->tss.kregs;
-	struct thread_struct *t = &tsk->tss;
-	int v;
-	
-	if(offset >= 1024)
-		offset -= 1024; /* whee... */
-	if(offset & ((sizeof(unsigned int) - 1))) {
-		pt_error_return(regs, EIO);
-		return;
-	}
-	if(offset >= 16 && offset < 784) {
-		offset -= 16; offset >>= 2;
-		if (t->w_saved)
-			pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
-		return;
-	}
-	if(offset >= 784 && offset < 832) {
-		offset -= 784; offset >>= 2;
-		if (t->w_saved)
-			pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
-		return;
-	}
-	switch(offset) {
-	case 0:
-		v = t->ksp;
-		break;
-#if 0
-	case 4:
-		v = t->kpc;
-		break;
-#endif
-	case 8:
-		v = t->kpsr;
-		break;
-	case 12:
-		v = t->uwinmask;
-		break;
-	case 832:
-		v = t->w_saved;
-		break;
-	case 896:
-		v = cregs->u_regs[UREG_I0];
-		break;
-	case 900:
-		v = cregs->u_regs[UREG_I1];
-		break;
-	case 904:
-		v = cregs->u_regs[UREG_I2];
-		break;
-	case 908:
-		v = cregs->u_regs[UREG_I3];
-		break;
-	case 912:
-		v = cregs->u_regs[UREG_I4];
-		break;
-	case 916:
-		v = cregs->u_regs[UREG_I5];
-		break;
-	case 920:
-		v = cregs->u_regs[UREG_I6];
-		break;
-	case 924:
-		if(tsk->tss.flags & MAGIC_CONSTANT)
-			v = cregs->u_regs[UREG_G1];
-		else
-			v = 0;
-		break;
-	case 940:
-		v = cregs->u_regs[UREG_I0];
-		break;
-	case 944:
-		v = cregs->u_regs[UREG_I1];
-		break;
-
-	case 948:
-		/* Isn't binary compatibility _fun_??? */
-		if(cregs->psr & PSR_C)
-			v = cregs->u_regs[UREG_I0] << 24;
-		else
-			v = 0;
-		break;
-
-		/* Rest of them are completely unsupported. */
-	default:
-		printk("%s [%d]: Wants to read user offset %ld\n",
-		       current->comm, current->pid, offset);
-		pt_error_return(regs, EIO);
-		return;
-	}
-	pt_os_succ_return_linux (regs, v, addr);
-	return;
-}
-
-static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
-				    struct task_struct *tsk)
-{
-	struct pt_regs *cregs = tsk->tss.kregs;
-	struct thread_struct *t = &tsk->tss;
-	unsigned int value = regs->u_regs[UREG_I3];
-
-	if(offset >= 1024)
-		offset -= 1024; /* whee... */
-	if(offset & ((sizeof(unsigned long) - 1)))
-		goto failure;
-	if(offset >= 16 && offset < 784) {
-		offset -= 16; offset >>= 2;
-		if (t->w_saved)
-			*(((unsigned long *)(&t->reg_window[0]))+offset) = value;
-		goto success;
-	}
-	if(offset >= 784 && offset < 832) {
-		offset -= 784; offset >>= 2;
-		if (t->w_saved)
-			*(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
-		goto success;
-	}
-	switch(offset) {
-	case 896:
-		cregs->u_regs[UREG_I0] = value;
-		break;
-	case 900:
-		cregs->u_regs[UREG_I1] = value;
-		break;
-	case 904:
-		cregs->u_regs[UREG_I2] = value;
-		break;
-	case 908:
-		cregs->u_regs[UREG_I3] = value;
-		break;
-	case 912:
-		cregs->u_regs[UREG_I4] = value;
-		break;
-	case 916:
-		cregs->u_regs[UREG_I5] = value;
-		break;
-	case 920:
-		cregs->u_regs[UREG_I6] = value;
-		break;
-	case 924:
-		cregs->u_regs[UREG_I7] = value;
-		break;
-	case 940:
-		cregs->u_regs[UREG_I0] = value;
-		break;
-	case 944:
-		cregs->u_regs[UREG_I1] = value;
-		break;
-
-		/* Rest of them are completely unsupported or "no-touch". */
-	default:
-		printk("%s [%d]: Wants to write user offset %ld\n",
-		       current->comm, current->pid, offset);
-		goto failure;
-	}
-success:
-	pt_succ_return(regs, 0);
-	return;
-failure:
-	pt_error_return(regs, EIO);
-	return;
-}
-#endif
-
 /* #define ALLOW_INIT_TRACING */
 /* #define DEBUG_PTRACE */
 
@@ -642,76 +237,54 @@
 	switch(request) {
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: {
-		unsigned long tmp;
-		int res;
+		unsigned long tmp64;
+		unsigned int tmp32;
+		int res, copied;
 
-		/* Non-word alignment _not_ allowed on Sparc. */
+		res = -EIO;
 		if (current->tss.flags & SPARC_FLAG_32BIT) {
-			unsigned int x;
-			if(addr & (sizeof(unsigned int) - 1)) {
-				pt_error_return(regs, EINVAL);
-				goto out;
-			}
-			down(&child->mm->mmap_sem);
-			res = read_int(child, addr, &x);
-			up(&child->mm->mmap_sem);
-			tmp = x;
+			copied = access_process_vm(child, addr,
+						   &tmp32, sizeof(tmp32), 0);
+			tmp64 = (unsigned long) tmp32;
+			if (copied == sizeof(tmp32))
+				res = 0;
 		} else {
-			if(addr & (sizeof(unsigned long) - 1)) {
-				pt_error_return(regs, EINVAL);
-				goto out;
-			}
-			down(&child->mm->mmap_sem);
-			res = read_long(child, addr, &tmp);
-			up(&child->mm->mmap_sem);
+			copied = access_process_vm(child, addr,
+						   &tmp64, sizeof(tmp64), 0);
+			if (copied == sizeof(tmp64))
+				res = 0;
 		}
-		if (res < 0) {
+		if (res < 0)
 			pt_error_return(regs, -res);
-			goto out;
-		}
-		pt_os_succ_return(regs, tmp, (long *) data);
-		goto out;
+		else
+			pt_os_succ_return(regs, tmp64, (long *) data);
+		goto flush_and_out;
 	}
 
-	case PTRACE_PEEKUSR:
-#if 0	
-		read_sunos_user(regs, addr, child, (long *) data);
-#endif
-		goto out;
-
-	case PTRACE_POKEUSR:
-#if 0	
-		write_sunos_user(regs, addr, child);
-#endif		
-		goto out;
-
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA: {
-		int res;
+		unsigned long tmp64;
+		unsigned int tmp32;
+		int copied, res = -EIO;
 
-		/* Non-word alignment _not_ allowed on Sparc. */
 		if (current->tss.flags & SPARC_FLAG_32BIT) {
-			if(addr & (sizeof(unsigned int) - 1)) {
-				pt_error_return(regs, EINVAL);
-				goto out;
-			}
-			down(&child->mm->mmap_sem);
-			res = write_int(child, addr, data);
-			up(&child->mm->mmap_sem);
+			tmp32 = data;
+			copied = access_process_vm(child, addr,
+						   &tmp32, sizeof(tmp32), 1);
+			if (copied == sizeof(tmp32))
+				res = 0;
 		} else {
-			if(addr & (sizeof(unsigned long) - 1)) {
-				pt_error_return(regs, EINVAL);
-				goto out;
-			}
-			down(&child->mm->mmap_sem);
-			res = write_long(child, addr, data);
-			up(&child->mm->mmap_sem);
+			tmp64 = data;
+			copied = access_process_vm(child, addr,
+						   &tmp64, sizeof(tmp64), 1);
+			if (copied == sizeof(tmp64))
+				res = 0;
 		}
 		if(res < 0)
 			pt_error_return(regs, -res);
 		else
 			pt_succ_return(regs, res);
-		goto out;
+		goto flush_and_out;
 	}
 
 	case PTRACE_GETREGS: {
@@ -926,98 +499,31 @@
 
 	case PTRACE_READTEXT:
 	case PTRACE_READDATA: {
-		unsigned char *dest = (unsigned char *) addr2;
-		unsigned long src = addr;
-		int len = data, curlen;
-		struct vm_area_struct *vma;
-		pte_t *pgtable;
-		unsigned long page;
-
-		while(len) {
-			down(&child->mm->mmap_sem);
-			vma = find_extend_vma(child, src);
-			if (!vma) {
-				up(&child->mm->mmap_sem);
-				pt_error_return(regs, EIO);
-				goto flush_and_out;
-			}
-			pgtable = ptrace_get_page (child, vma, src, 0);
-			up(&child->mm->mmap_sem);
-			if (src & ~PAGE_MASK) {
-				curlen = PAGE_SIZE - (src & ~PAGE_MASK);
-				if (curlen > len) curlen = len;
-			} else if (len > PAGE_SIZE)
-				curlen = PAGE_SIZE;
-			else
-				curlen = len;
-			if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) {
-				if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) {
-					flush_page_to_ram(page);
-					pt_error_return(regs, EFAULT);
-					goto flush_and_out;
-				}
-				flush_page_to_ram(page);
-			} else {
-				if (clear_user (dest, curlen)) {
-					pt_error_return(regs, EFAULT);
-					goto flush_and_out;
-				}
-			}
-			src += curlen;
-			dest += curlen;
-			len -= curlen;
+		int res = ptrace_readdata(child, addr,
+					  (void *)addr2, data);
+		if (res == data) {
+			pt_succ_return(regs, 0);
+			goto flush_and_out;
 		}
-		pt_succ_return(regs, 0);
+		if (res >= 0)
+			res = -EIO;
+		pt_error_return(regs, -res);
 		goto flush_and_out;
 	}
 
 	case PTRACE_WRITETEXT:
 	case PTRACE_WRITEDATA: {
-		unsigned char *src = (unsigned char *) addr2;
-		unsigned long dest = addr;
-		int len = data, curlen;
-		struct vm_area_struct *vma;
-		pte_t *pgtable;
-		unsigned long page;
-
-		while(len) {
-			down(&child->mm->mmap_sem);
-			vma = find_extend_vma(child, dest);
-			if (!vma) {
-				up(&child->mm->mmap_sem);
-				pt_error_return(regs, EIO);
-				goto flush_and_out;
-			}
-			pgtable = ptrace_get_page (child, vma, dest, 1);
-			up(&child->mm->mmap_sem);
-			if (dest & ~PAGE_MASK) {
-				curlen = PAGE_SIZE - (dest & ~PAGE_MASK);
-				if (curlen > len) curlen = len;
-			} else if (len > PAGE_SIZE)
-				curlen = PAGE_SIZE;
-			else
-				curlen = len;
-			if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) {
-				flush_cache_page(vma, dest);
-				if (copy_from_user (((char *)page) + (dest & ~PAGE_MASK), src, curlen)) {
-					flush_page_to_ram(page);
-					set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-					flush_tlb_page(vma, dest);
-					pt_error_return(regs, EFAULT);
-					goto flush_and_out;
-				}
-				flush_page_to_ram(page);
-				set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-				flush_tlb_page(vma, dest);
-			}
-			src += curlen;
-			dest += curlen;
-			len -= curlen;
+		int res = ptrace_writedata(child, (void *) addr2,
+					   addr, data);
+		if (res == data) {
+			pt_succ_return(regs, 0);
+			goto flush_and_out;
 		}
-		pt_succ_return(regs, 0);
+		if (res >= 0)
+			res = -EIO;
+		pt_error_return(regs, -res);
 		goto flush_and_out;
 	}
-
 	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
 		addr = 1;
 
@@ -1105,6 +611,14 @@
 		unsigned long va;
 		for(va =  0; va < (PAGE_SIZE << 1); va += 32)
 			spitfire_put_dcache_tag(va, 0x0);
+		if (request == PTRACE_PEEKTEXT ||
+		    request == PTRACE_POKETEXT ||
+		    request == PTRACE_READTEXT ||
+		    request == PTRACE_WRITETEXT) {
+			for(va =  0; va < (PAGE_SIZE << 1); va += 32)
+				spitfire_put_icache_tag(va, 0x0);
+			__asm__ __volatile__("flush %g6");
+		}
 	}
 out:
 	unlock_kernel();
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.9/linux/arch/sparc64/kernel/smp.c	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/kernel/smp.c	Thu Jul  1 15:09:01 1999
@@ -615,7 +615,7 @@
 				unsigned int *inc, *inc2;
 
 				update_one_process(current, 1, user, !user, cpu);
-				if(--current->counter < 0) {
+				if(--current->counter <= 0) {
 					current->counter = 0;
 					current->need_resched = 1;
 				}
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.9/linux/arch/sparc64/kernel/sparc64_ksyms.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jul  5 20:35:18 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.59 1999/06/28 11:28:50 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.60 1999/07/03 22:11:12 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7 +45,6 @@
 #include <asm/ebus.h>
 #endif
 #include <asm/a.out.h>
-#include <asm/svr4.h>
 
 struct poll {
 	int fd;
@@ -118,6 +117,12 @@
 
 /* used by various drivers */
 #ifdef __SMP__
+/* Out of line rw-locking implementation. */
+EXPORT_SYMBOL_PRIVATE(read_lock);
+EXPORT_SYMBOL_PRIVATE(read_unlock);
+EXPORT_SYMBOL_PRIVATE(write_lock);
+EXPORT_SYMBOL_PRIVATE(write_unlock);
+
 /* Kernel wide locking */
 EXPORT_SYMBOL(kernel_flag);
 
@@ -157,6 +162,10 @@
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(local_bh_count);
 #endif
+
+/* Atomic counter implementation. */
+EXPORT_SYMBOL_PRIVATE(atomic_add);
+EXPORT_SYMBOL_PRIVATE(atomic_sub);
 
 EXPORT_SYMBOL(ivector_table);
 EXPORT_SYMBOL(enable_irq);
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.9/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Tue Jul  6 10:11:40 1999
@@ -17,7 +17,6 @@
 #include <linux/utime.h>
 #include <linux/resource.h>
 #include <linux/times.h>
-#include <linux/utime.h>
 #include <linux/utsname.h>
 #include <linux/timex.h>
 #include <linux/smp.h>
@@ -32,18 +31,15 @@
 #include <linux/smb_mount.h>
 #include <linux/ncp_fs.h>
 #include <linux/quota.h>
-#include <linux/file.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/nfsd/syscall.h>
-#include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/personality.h>
 #include <linux/stat.h>
-#include <linux/timex.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -2328,8 +2324,8 @@
 			break;
 		}
 		/* Bump the usage count and install the file. */
-		atomic_inc(&fp[i]->f_count);
-		current->files->fd[new_fd] = fp[i];
+		get_file(fp[i]);
+		fd_install(new_fd, fp[i]);
 	}
 
 	if (i > 0) {
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.9/linux/arch/sparc64/kernel/sys_sunos32.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Tue Jul  6 10:11:40 1999
@@ -25,7 +25,6 @@
 #include <linux/signal.h>
 #include <linux/uio.h>
 #include <linux/utsname.h>
-#include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
@@ -712,7 +711,7 @@
 	struct inode  *inode;
 	struct file   *file;
 
-	file = current->files->fd [fd];
+	file = fcheck(fd);
 	if(!file)
 		return 0;
 
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.3.9/linux/arch/sparc64/lib/Makefile	Tue Oct 27 09:52:20 1998
+++ linux/arch/sparc64/lib/Makefile	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $
+# $Id: Makefile,v 1.19 1999/07/03 22:11:08 davem Exp $
 # Makefile for Sparc library files..
 #
 
@@ -6,7 +6,8 @@
 
 OBJS  = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
 	memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-	VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o
+	VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o \
+	atomic.o rwlock.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/lib/atomic.S linux/arch/sparc64/lib/atomic.S
--- v2.3.9/linux/arch/sparc64/lib/atomic.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/atomic.S	Sun Jul  4 09:53:12 1999
@@ -0,0 +1,32 @@
+/* $Id: atomic.S,v 1.1 1999/07/03 22:11:04 davem Exp $
+ * atomic.S: These things are too big to do inline.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/asi.h>
+
+	.text
+	.align	64
+
+	.globl	__atomic_add
+__atomic_add:
+	lduw	[%g1], %g5
+	add	%g5, %g2, %g7
+	cas	[%g1], %g5, %g7
+	cmp	%g5, %g7
+	bne,pn	%icc, __atomic_add
+	 nop
+	jmpl	%g3 + 8, %g0
+	 add	%g7, %g2, %g2
+
+	.globl	__atomic_sub
+__atomic_sub:
+	lduw	[%g1], %g5
+	sub	%g5, %g2, %g7
+	cas	[%g1], %g5, %g7
+	cmp	%g5, %g7
+	bne,pn	%icc, __atomic_sub
+	 nop
+	jmpl	%g3 + 8, %g0
+	 sub	%g7, %g2, %g2
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/lib/rwlock.S linux/arch/sparc64/lib/rwlock.S
--- v2.3.9/linux/arch/sparc64/lib/rwlock.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/rwlock.S	Sun Jul  4 09:53:12 1999
@@ -0,0 +1,81 @@
+/* $Id: rwlock.S,v 1.1 1999/07/03 22:11:06 davem Exp $
+ * rwlocks.S: These things are too big to do inline.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+	.text
+	.align	64
+
+	/* The non-contention read lock usage is 2 cache lines. */
+
+	.globl	__read_lock, __read_unlock
+	/* g1=lock, g3=retpc, g5/g7=scratch */
+__read_lock:
+	ldsw		[%g1], %g5
+	brlz,pn		%g5, __read_wait_for_writer
+4:	 add		%g5, 1, %g7
+	cas		[%g1], %g5, %g7
+	cmp		%g5, %g7
+	bne,pn		%icc, __read_lock
+	 membar		#StoreLoad | #StoreStore
+99:	jmpl		%g3 + 8, %g0
+	 nop
+__read_unlock:
+	lduw		[%g1], %g5
+	sub		%g5, 1, %g7
+	cas		[%g1], %g5, %g7
+	cmp		%g5, %g7
+	be,pt		%xcc, 99b
+	 membar		#StoreLoad | #StoreStore
+	b,a,pt		%xcc, __read_unlock
+
+__read_wait_for_writer:
+	ldsw		[%g1], %g5
+	brlz,pt		%g5, __read_wait_for_writer
+	 membar		#LoadLoad
+	b,a,pt		%xcc, 4b
+__write_wait_for_writer:
+	ldsw		[%g1], %g5
+	brlz,pt		%g5, __write_wait_for_writer
+	 membar		#LoadLoad
+	b,a,pt		%xcc, 4f
+
+	/* Similarly, 2 cache lines for non-contention write locks. */
+
+	.align		64
+	.globl		__write_unlock
+	/* g1=lock, g3=retpc, g2/g5/g7=scratch */
+__write_unlock:
+	sethi		%hi(0x80000000), %g2
+1:	lduw		[%g1], %g5
+	andn		%g5, %g2, %g7
+	cas		[%g1], %g5, %g7
+	cmp		%g5, %g7
+	be,pt		%icc, 99b
+	 membar		#StoreLoad | #StoreStore
+	b,a,pt		%xcc, 1b
+
+	.globl		__write_lock
+__write_lock:
+	sethi		%hi(0x80000000), %g2
+1:	ldsw		[%g1], %g5
+4:	brnz,pn		%g5, 5f
+	 or		%g5, %g2, %g7
+	cas		[%g1], %g5, %g7
+	cmp		%g5, %g7
+	be,pt		%icc, 99b
+	 membar		#StoreLoad | #StoreStore
+
+	b,a,pt		%xcc, 1b
+5:	brlz		%g5, __write_wait_for_writer
+	or		%g5, %g2, %g7
+	cas		[%g1], %g5, %g7
+	cmp		%g5, %g7
+	bne,pn		%icc, 5b
+8:	 ldsw		[%g1], %g5
+	cmp		%g5, %g2
+	be,pn		%icc, 99b
+	 membar		#LoadLoad
+	b,a,pt		%xcc, 99b
+
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c
--- v2.3.9/linux/arch/sparc64/mm/asyncd.c	Wed May 12 08:41:12 1999
+++ linux/arch/sparc64/mm/asyncd.c	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.6 1999/05/12 11:11:48 davem Exp $
+/*  $Id: asyncd.c,v 1.8 1999/07/04 04:35:55 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.3.9/linux/arch/sparc64/mm/fault.c	Tue Mar 16 21:52:06 1999
+++ linux/arch/sparc64/mm/fault.c	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $
+/* $Id: fault.c,v 1.36 1999/07/04 04:35:56 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)
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/solaris/ioctl.c linux/arch/sparc64/solaris/ioctl.c
--- v2.3.9/linux/arch/sparc64/solaris/ioctl.c	Wed May 26 18:14:37 1999
+++ linux/arch/sparc64/solaris/ioctl.c	Tue Jul  6 10:11:40 1999
@@ -367,15 +367,8 @@
 static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg,
                                     int len, int *len_p)
 {
-        struct file *filp;
         struct inode *ino;
 	int ret;
-
-        filp = current->files->fd[fd];
-        if (! filp ||
-	    ! (ino = filp->f_dentry->d_inode) ||
-	    ! ino->i_sock)
-		return TBADF;
 		
 	switch (cmd & 0xff) {
 	case 141: /* TI_OPTMGMT */
@@ -459,7 +452,7 @@
 	return TNOTSUPPORT;
 }
 
-static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg)
+static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd, u32 arg)
 {
 	char *p;
 	int ret;
@@ -470,9 +463,7 @@
         struct sol_socket_struct *sock;
         struct module_info *mi;
 
-        filp = current->files->fd[fd];
-        if (! filp ||
-	    ! (ino = filp->f_dentry->d_inode) ||
+        if (! (ino = filp->f_dentry->d_inode) ||
 	    ! ino->i_sock)
 		return -EBADF;
         sock = filp->private_data;
@@ -696,14 +687,14 @@
 	struct file *filp;
 	int error = -EBADF;
 
-	lock_kernel();
-	filp = fcheck(fd);
+	filp = fget(fd);
 	if (!filp)
 		goto out;
 
+	lock_kernel();
 	error = -EFAULT;
 	switch ((cmd >> 8) & 0xff) {
-	case 'S': error = solaris_S(fd, cmd, arg); break;
+	case 'S': error = solaris_S(filp, fd, cmd, arg); break;
 	case 'T': error = solaris_T(fd, cmd, arg); break;
 	case 'i': error = solaris_i(fd, cmd, arg); break;
 	case 'r': error = solaris_r(fd, cmd, arg); break;
@@ -714,6 +705,8 @@
 		error = -ENOSYS;
 		break;
 	}
+	unlock_kernel();
+	fput(filp);
 out:
 	if (error == -ENOSYS) {
 		unsigned char c = cmd>>8;
@@ -723,6 +716,5 @@
 		       (int)fd, (unsigned int)cmd, c, (unsigned int)arg);
 		error = -EINVAL;
 	}
-	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c
--- v2.3.9/linux/arch/sparc64/solaris/socksys.c	Sun Oct  4 10:22:43 1998
+++ linux/arch/sparc64/solaris/socksys.c	Mon Jul  5 20:35:18 1999
@@ -16,7 +16,6 @@
 #include <linux/file.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/file.h>
 #include <linux/malloc.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c
--- v2.3.9/linux/drivers/acorn/char/keyb_arc.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/char/keyb_arc.c	Mon Jul  5 20:35:18 1999
@@ -22,7 +22,6 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/kbd_ll.h>
-#include <linux/tty.h>
 #include <linux/kbd_kern.h>
 #include <linux/delay.h>
 
diff -u --recursive --new-file v2.3.9/linux/drivers/ap1000/bif.c linux/drivers/ap1000/bif.c
--- v2.3.9/linux/drivers/ap1000/bif.c	Fri May  8 00:47:24 1998
+++ linux/drivers/ap1000/bif.c	Mon Jul  5 20:35:18 1999
@@ -30,7 +30,6 @@
 #include <asm/io.h>
 
 #include <linux/inet.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c
--- v2.3.9/linux/drivers/ap1000/ringbuf.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/ap1000/ringbuf.c	Sun Jul  4 10:02:30 1999
@@ -318,6 +318,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
diff -u --recursive --new-file v2.3.9/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.9/linux/drivers/block/Config.in	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/Config.in	Mon Jul  5 19:52:13 1999
@@ -41,30 +41,49 @@
         bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
         if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
           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
+          fi
         fi
         bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
         bool '     AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+          bool '     ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
+          bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
+          bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
+        fi
+        bool '     HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+             "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+          bool '       HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
+        fi
+        bool '     Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+             "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+          bool '       PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
+        fi
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+          bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
+        fi
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
-          bool '     Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX
-          if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
-            bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
-            bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
-            bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
-            bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
-            bool '     ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
-            bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
-            bool '     PDC20246 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20246
-            bool '     PDC20262 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20262
-            if [ "$CONFIG_BLK_DEV_PDC20246" = "y" -o \
-                 "$CONFIG_BLK_DEV_PDC20262" = "y" ]; then
-              define_bool CONFIG_BLK_DEV_PDC202XX y
-            else
-              define_bool CONFIG_BLK_DEV_PDC202XX n
-            fi
-            bool '     HPT343 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT343
+        fi
+        if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+          bool '     PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
+          if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
+               "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+            bool '       Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT
+            bool '       Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE
           fi
         fi
+        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
+        fi
       fi
       if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
@@ -106,13 +125,12 @@
       bool '     ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
       bool '     DTC-2278 support' CONFIG_BLK_DEV_DTC2278
       bool '     Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+      if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
+           "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+      fi
       bool '     QDI QD6580 support' CONFIG_BLK_DEV_QD6580
       bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then
-          bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-        fi
-      fi
     fi
     if [ "$CONFIG_AMIGA" = "y" ]; then
       bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
@@ -145,6 +163,7 @@
     dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
   fi
 fi
+tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
 
 comment 'Additional Block Devices'
 
@@ -182,13 +201,13 @@
   source drivers/block/paride/Config.in
 fi
 
-
-if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \
-     "$CONFIG_IDE_CHIPSETS" = "y" -o \
-     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
-     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
+     "$CONFIG_BLK_DEV_CMD640" = "y" -o \
      "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
-     "$CONFIG_BLK_DEV_HPT343" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
+     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
   define_bool CONFIG_BLK_DEV_IDE_MODES y
diff -u --recursive --new-file v2.3.9/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.9/linux/drivers/block/Makefile	Wed May 26 09:30:31 1999
+++ linux/drivers/block/Makefile	Mon Jul  5 19:52:13 1999
@@ -202,8 +202,8 @@
 IDE_OBJS += aec6210.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_HPT343),y)
-IDE_OBJS += hpt343.o
+ifeq ($(CONFIG_BLK_DEV_HPT34X),y)
+IDE_OBJS += hpt34x.o
 endif
 
 ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
@@ -271,6 +271,14 @@
 else
   ifeq ($(CONFIG_BLK_DEV_XD),m)
   M_OBJS += xd.o
+  endif
+endif
+
+ifeq ($(CONFIG_BLK_CPQ_DA),y)
+L_OBJS += cpqarray.o
+else
+  ifeq ($(CONFIG_BLK_CPQ_DA),m)
+  M_OBJS += cpqarray.o
   endif
 endif
 
diff -u --recursive --new-file v2.3.9/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c
--- v2.3.9/linux/drivers/block/alim15x3.c	Wed May 26 16:55:40 1999
+++ linux/drivers/block/alim15x3.c	Thu Jul  1 10:25:38 1999
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/alim15x3.c	Version 0.04	Feb. 8, 1999
+ * linux/drivers/block/alim15x3.c	Version 0.05	Jun. 29, 1999
  *
  *  Copyright (C) 1998-99 Michel Aubry, Maintainer
  *  Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
@@ -20,6 +20,8 @@
 
 #include <asm/io.h>
 
+#include "ide_modes.h"
+
 #define DISPLAY_ALI_TIMINGS
 
 #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
@@ -59,6 +61,55 @@
 };
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	byte s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = ide_system_bus_speed();
+	int port = hwif->index ? 0x5c : 0x58;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+		r_clc = 0;
+	}
+	save_flags(flags);
+	cli();
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	restore_flags(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
 __initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name))
 {
 	byte confreg0 = 0, confreg1 =0, progif = 0;
@@ -146,19 +197,22 @@
 __initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif))
 {
 	struct pci_dev *dev;
-	byte ideic, inmir;
+	byte ideic, inmir, iderev;
 	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
 				      1, 11, 0, 12, 0, 14, 0, 15 };
+
+	pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev);
+
 	hwif->irq = hwif->channel ? 15 : 14;
 	for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */
 		if (dev->vendor==PCI_VENDOR_ID_AL &&
-		   dev->device==PCI_DEVICE_ID_AL_M1533)
+		    dev->device==PCI_DEVICE_ID_AL_M1533)
 			break;
 	if (dev) {			
 		pci_read_config_byte(dev, 0x58, &ideic);
 		ideic = ideic & 0x03;
 		if ((hwif->channel && ideic == 0x03) ||
-		   (!hwif->channel && !ideic)) {
+		    (!hwif->channel && !ideic)) {
 			pci_read_config_byte(dev, 0x44, &inmir);
 			inmir = inmir & 0x0f;
 			hwif->irq = irq_routing_table[inmir];
@@ -174,8 +228,15 @@
 	ali_display_info = &ali_get_info;
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-	if (hwif->dma_base)
+	hwif->tuneproc = &ali15x3_tune_drive;
+	if ((hwif->dma_base) && (iderev >= 0xC1)) {
+		/* M1543C or newer for DMAing */
 		hwif->dmaproc = &ali15x3_dmaproc;
+	} else {
+		hwif->autodma = 0;
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
 	return;
 }
 
diff -u --recursive --new-file v2.3.9/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.3.9/linux/drivers/block/amiflop.c	Tue May 11 23:33:42 1999
+++ linux/drivers/block/amiflop.c	Tue Jul  6 19:05:48 1999
@@ -1755,13 +1755,13 @@
 	NULL,			/* revalidate */
 };
 
-__initfunc(void amiga_floppy_setup (char *str, int *ints))
+void __init amiga_floppy_setup (char *str, int *ints)
 {
 	printk (KERN_INFO "amiflop: Setting default df0 to %x\n", ints[1]);
 	fd_def_df0 = ints[1];
 }
 
-__initfunc(static int fd_probe_drives(void))
+static int __init fd_probe_drives(void)
 {
 	int drive,drives,nomem;
 
@@ -1791,7 +1791,7 @@
 	return -ENOMEM;
 }
 
-__initfunc(int amiga_floppy_init(void))
+int __init amiga_floppy_init(void)
 {
   int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.3.9/linux/drivers/block/ataflop.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/ataflop.c	Tue Jul  6 19:05:48 1999
@@ -1771,7 +1771,7 @@
 
 /* Initialize the 'unit' variable for drive 'drive' */
 
-__initfunc(static void fd_probe( int drive ))
+static void __init fd_probe( int drive )
 {
 	UD.connected = 0;
 	UDT  = NULL;
@@ -1814,7 +1814,7 @@
  * declared absent.
  */
 
-__initfunc(static int fd_test_drive_present( int drive ))
+static int __init fd_test_drive_present( int drive )
 {
 	unsigned long timeout;
 	unsigned char status;
@@ -1861,7 +1861,7 @@
  * floppies, additionally start the disk-change and motor-off timers.
  */
 
-__initfunc(static void config_types( void ))
+static void __init config_types( void )
 {
 	int drive, cnt = 0;
 
@@ -2006,7 +2006,7 @@
 	floppy_revalidate,	/* revalidate */
 };
 
-__initfunc(int atari_floppy_init (void))
+int __init atari_floppy_init (void)
 {
 	int i;
 
@@ -2075,7 +2075,7 @@
 }
 
 
-__initfunc(void atari_floppy_setup( char *str, int *ints ))
+void __init atari_floppy_setup( char *str, int *ints )
 {
 	int i;
 	
diff -u --recursive --new-file v2.3.9/linux/drivers/block/cmd646.c linux/drivers/block/cmd646.c
--- v2.3.9/linux/drivers/block/cmd646.c	Thu May 27 09:55:21 1999
+++ linux/drivers/block/cmd646.c	Tue Jul  6 19:05:48 1999
@@ -1,4 +1,4 @@
-/* $Id: cmd646.c,v 1.13 1999/05/27 04:49:38 davem Exp $
+/* $Id: cmd646.c,v 1.14 1999/07/03 08:56:09 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.
@@ -94,6 +94,9 @@
 
 static void cmd646_do_setfeature(ide_drive_t *drive, byte command)
 {
+#if 0
+	(void) ide_config_drive_speed(drive, command);
+#else
 	unsigned long flags;
 	byte old_select;
 
@@ -116,6 +119,7 @@
 out:
 	OUT_BYTE(old_select, IDE_SELECT_REG);
 	restore_flags(flags);
+#endif
 }
 
 static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
@@ -236,7 +240,7 @@
 	return cmd646_dmaproc(func, drive);
 }
 
-__initfunc(void ide_init_cmd646 (ide_hwif_t *hwif))
+void __init ide_init_cmd646 (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned char mrdmode;
diff -u --recursive --new-file v2.3.9/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.9/linux/drivers/block/cpqarray.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/cpqarray.c	Tue Jul  6 10:11:40 1999
@@ -0,0 +1,1730 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  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.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/blkpg.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/hdreg.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+
+#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
+
+#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.4)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,4)
+#define MAJOR_NR COMPAQ_SMART2_MAJOR
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#include "cpqarray.h"
+#include "ida_cmd.h"
+#include "smart1,2.h"
+#include "ida_ioctl.h"
+
+#define READ_AHEAD	128
+#define NR_CMDS		128 /* This could probably go as high as ~400 */
+
+#define MAX_CTLR	8
+#define CTLR_SHIFT	8
+
+static int nr_ctlr = 0;
+static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static int eisa[8] = { 0, 0 ,0 ,0, 0, 0 ,0 ,0 };
+
+#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))
+
+/*  board_id = Subsystem Device ID & Vendor ID
+ *  product = Marketing Name for the board
+ *  access = Address of the struct of function pointers 
+ */
+struct board_type products[] = {
+	{ 0x0040110E, "IDA",			&smart1_access },
+	{ 0x0140110E, "IDA-2",			&smart1_access },
+	{ 0x1040110E, "IAES",			&smart1_access },
+	{ 0x2040110E, "SMART",			&smart1_access },
+	{ 0x3040110E, "SMART-2/E",		&smart2e_access },
+	{ 0x40300E11, "SMART-2/P",		&smart2_access },
+	{ 0x40310E11, "SMART-2SL",		&smart2_access },
+	{ 0x40320E11, "Smart Array 3200",	&smart2_access },
+	{ 0x40330E11, "Smart Array 3100ES",	&smart2_access },
+	{ 0x40340E11, "Smart Array 221",	&smart2_access },
+	{ 0x40400E11, "Integrated Array",	&smart4_access },
+	{ 0x40500E11, "Smart Array 4200",	&smart4_access },
+	{ 0x40510E11, "Smart Array 4250ES",	&smart4_access },
+};
+
+static struct hd_struct * ida;
+static int * ida_sizes;
+static int * ida_blocksizes;
+static int * ida_hardsizes;
+static struct gendisk ida_gendisk[MAX_CTLR];
+
+struct proc_dir_entry *proc_array = NULL;
+
+/* Debug... */
+#define DBG(s)	do { s } while(0)
+/* Debug (general info)... */
+#define DBGINFO(s) do { } while(0)
+/* Debug Paranoid... */
+#define DBGP(s)  do { } while(0)
+/* Debug Extra Paranoid... */
+#define DBGPX(s) do { } while(0)
+
+void cpqarray_init(void);
+static int cpqarray_pci_detect(void);
+static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
+static ulong remap_pci_mem(ulong base, ulong size);
+static int cpqarray_eisa_detect(void);
+static int pollcomplete(int ctlr);
+static void getgeometry(int ctlr);
+static void start_fwbk(int ctlr);
+
+static cmdlist_t * cmd_alloc(ctlr_info_t *h);
+static void cmd_free(ctlr_info_t *h, cmdlist_t *c);
+
+static int sendcmd(
+	__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int blk,
+	unsigned int blkcnt,
+	unsigned int log_unit );
+
+static int ida_open(struct inode *inode, struct file *filep);
+static int ida_release(struct inode *inode, struct file *filep);
+static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
+static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+
+static void do_ida_request(int i);
+/*
+ * This is a hack.  This driver eats a major number for each controller, and
+ * sets blkdev[xxx].request_fn to each one of these so the real request
+ * function knows what controller its working with.
+ */
+#define DO_IDA_REQUEST(x) { do_ida_request(x); }
+
+static void do_ida_request0(void) DO_IDA_REQUEST(0);
+static void do_ida_request1(void) DO_IDA_REQUEST(1);
+static void do_ida_request2(void) DO_IDA_REQUEST(2);
+static void do_ida_request3(void) DO_IDA_REQUEST(3);
+static void do_ida_request4(void) DO_IDA_REQUEST(4);
+static void do_ida_request5(void) DO_IDA_REQUEST(5);
+static void do_ida_request6(void) DO_IDA_REQUEST(6);
+static void do_ida_request7(void) DO_IDA_REQUEST(7);
+
+static void start_io(ctlr_info_t *h);
+
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline void complete_buffers(struct buffer_head *bh, int ok);
+static inline void complete_command(cmdlist_t *cmd, int timeout);
+
+static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void ida_timer(unsigned long tdata);
+static int frevalidate_logvol(kdev_t dev);
+static int revalidate_logvol(kdev_t dev, int maxusage);
+static int revalidate_allvol(kdev_t dev);
+
+static void ida_procinit(int i);
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+
+static void ida_geninit(struct gendisk *g)
+{
+	int ctlr = g-ida_gendisk;
+	int i,j;
+	drv_info_t *drv;
+
+	for(i=0; i<NWD; i++) {
+		drv = &hba[ctlr]->drv[i];
+		if (!drv->nr_blks)
+			continue;
+		ida[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)].nr_sects =
+		ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =
+				drv->nr_blks;
+
+		for(j=0; j<16; j++) {
+			ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+				1024;
+			ida_hardsizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+				drv->blk_size;
+		}
+		ida_gendisk[ctlr].nr_real++;
+	}
+
+}
+
+struct file_operations ida_fops  = {
+	NULL,                        /* lseek - default */
+	block_read,                  /* read - general block-dev read */
+	block_write,                 /* write - general block-dev write */
+	NULL,                        /* readdir - bad */
+	NULL,                        /* select */
+	ida_ioctl,                  /* ioctl */
+	NULL,                        /* mmap */
+	ida_open,                     /* open code */
+	NULL,
+	ida_release,                  /* release */
+	block_fsync,	              /* fsync */
+	NULL,                        /* fasync */
+	NULL,			/* Disk change */
+	frevalidate_logvol,	/* revalidate */
+};
+
+
+/*
+ * Get us a file in /proc/array that says something about each controller.
+ * Create /proc/array if it doesn't exist yet.
+ */
+static void ida_procinit(int i)
+{
+	struct proc_dir_entry *pd;
+
+	if (proc_array == NULL) {
+		proc_array = create_proc_entry("array", S_IFDIR|S_IRUGO|S_IXUGO,
+								&proc_root);
+		if (!proc_array) return;
+	}
+
+	pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_array);
+	if (!pd) return;
+	pd->read_proc = ida_proc_get_info;
+	pd->data = hba[i];
+}
+
+/*
+ * Report information about this controller.
+ */
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h = (ctlr_info_t*)data;
+	drv_info_t *drv;
+#ifdef CPQ_PROC_PRINT_QUEUES
+	cmdlist_t *c;
+#endif
+
+	ctlr = h->ctlr;
+	size = sprintf(buffer, "%s:  Compaq %s Controller\n"
+		"       Board ID: %08lx\n"
+		"       Firmware Revision: %c%c%c%c\n"
+		"       Controller Sig: %08lx\n"
+		"       Memory Address: %08lx\n"
+		"       I/O Port: %04x\n"
+		"       IRQ: %x\n"
+		"       Logical drives: %d\n"
+		"       Physical drives: %d\n\n"
+		"       Current Q depth: %d\n"
+		"       Max Q depth since init: %d\n\n",
+		h->devname, 
+		h->product_name,
+		(unsigned long)h->board_id,
+		h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3],
+		(unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,
+		(unsigned int) h->ioaddr, (unsigned int)h->intr,
+		h->log_drives, h->phys_drives,
+		h->Qdepth, h->maxQsinceinit);
+
+	pos += size; len += size;
+	
+	size = sprintf(buffer+len, "Logical Drive Info:\n");
+	pos += size; len += size;
+
+	for(i=0; i<h->log_drives; i++) {
+		drv = &h->drv[i];
+		size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
+				ctlr, i, drv->blk_size, drv->nr_blks);
+		pos += size; len += size;
+	}
+
+#ifdef CPQ_PROC_PRINT_QUEUES
+	size = sprintf(buffer+len, "\nCurrent Queues:\n");
+	pos += size; len += size;
+
+	c = h->reqQ;
+	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
+	if (c) c=c->next;
+	while(c && c != h->reqQ) {
+		size = sprintf(buffer+len, "->%p", c);
+		pos += size; len += size;
+		c=c->next;
+	}
+
+	c = h->cmpQ;
+	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
+	if (c) c=c->next;
+	while(c && c != h->cmpQ) {
+		size = sprintf(buffer+len, "->%p", c);
+		pos += size; len += size;
+		c=c->next;
+	}
+
+	size = sprintf(buffer+len, "\n"); pos += size; len += size;
+#endif
+	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
+			h->nr_allocs, h->nr_frees);
+	pos += size; len += size;
+
+	*eof = 1;
+	*start = buffer+offset;
+	len -= offset;
+	if (len>length)
+		len = length;
+	return len;
+}
+
+#ifdef MODULE
+
+MODULE_PARM(eisa, "1-8i");
+EXPORT_NO_SYMBOLS;
+
+/* This is a bit of a hack... */
+int init_module(void)
+{
+	int i, j;
+	cpqarray_init();
+	if (nr_ctlr == 0)
+		return -EIO;
+
+	for(i=0; i<nr_ctlr; i++) {
+		ida_geninit(&ida_gendisk[i]); 
+		for(j=0; j<NWD; j++)	
+			if (ida_sizes[(i<<CTLR_SHIFT) + (j<<NWD_SHIFT)])
+				resetup_one_dev(&ida_gendisk[i], j);
+	}
+	return 0;
+}
+void cleanup_module(void)
+{
+	int i;
+	struct gendisk *g;
+
+	for(i=0; i<nr_ctlr; i++) {
+		hba[i]->access.set_intr_mask(hba[i], 0);
+		free_irq(hba[i]->intr, hba[i]);
+		iounmap((void*)hba[i]->vaddr);
+		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+		del_timer(&hba[i]->timer);
+		remove_proc_entry(hba[i]->devname, proc_array);
+		kfree(hba[i]->cmd_pool);
+		kfree(hba[i]->cmd_pool_bits);
+
+		if (gendisk_head == &ida_gendisk[i]) {
+			gendisk_head = ida_gendisk[i].next;
+		} else {
+			for(g=gendisk_head; g; g=g->next) {
+				if (g->next == &ida_gendisk[i]) {
+					g->next = ida_gendisk[i].next;
+					break;
+				}
+			}
+		}
+	}
+	remove_proc_entry("array", &proc_root);
+	kfree(ida);
+	kfree(ida_sizes);
+	kfree(ida_hardsizes);
+	kfree(ida_blocksizes);
+
+
+}
+#endif /* MODULE */
+
+/*
+ *  This is it.  Find all the controllers and register them.  I really hate
+ *  stealing all these major device numbers.
+ */
+void cpqarray_init(void)
+{
+	void (*request_fns[MAX_CTLR])(void) = {
+		do_ida_request0, do_ida_request1,
+		do_ida_request2, do_ida_request3,
+		do_ida_request4, do_ida_request5,
+		do_ida_request6, do_ida_request7,
+	};
+	int i;
+
+	/* detect controllers */
+	cpqarray_pci_detect();
+	cpqarray_eisa_detect();
+	
+	if (nr_ctlr == 0)
+		return;
+
+	printk(DRIVER_NAME "\n");
+	printk("Found %d controller(s)\n", nr_ctlr);
+
+	/* allocate space for disk structs */
+	ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);
+	
+	if(ida==NULL)
+		goto bail;
+	ida_sizes =      kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+	if(ida_sizes==NULL)
+		goto bail2;
+	ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+	if(ida_blocksizes==NULL)
+		goto bail3;
+	ida_hardsizes =  kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+	if(ida_hardsizes==NULL)
+		goto bail4;
+
+	memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
+	memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
+
+	/* 
+	 * register block devices
+	 * Find disks and fill in structs
+	 * Get an interrupt, set the Q depth and get into /proc
+	 */
+	for(i=0; i< nr_ctlr; i++) {
+		hba[i]->access.set_intr_mask(hba[i], 0);
+		if (request_irq(hba[i]->intr, do_ida_intr,
+			SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) {
+
+			printk("Unable to get irq %d for %s\n", 
+				hba[i]->intr, hba[i]->devname);
+			continue;
+		}
+		if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
+			printk("Unable to get major number %d for ida\n",
+				MAJOR_NR+i);
+			continue;
+		}
+
+		hba[i]->cmd_pool = (cmdlist_t *)kmalloc(
+				NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL);
+		hba[i]->cmd_pool_bits = (__u32*)kmalloc(
+				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+		
+		if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
+		{
+			int j;
+			if(hba[i]->cmd_pool_bits)
+				kfree(hba[i]->cmd_pool_bits);
+			if(hba[i]->cmd_pool)
+				kfree(hba[i]->cmd_pool);
+			for(j=0;i<i;j++)
+			{
+				free_irq(hba[j]->intr, hba[j]);
+				unregister_blkdev(MAJOR_NR+j, hba[j]->devname);
+				kfree(hba[j]->cmd_pool_bits);
+				kfree(hba[j]->cmd_pool);
+			}
+			free_irq(hba[i]->intr, hba[i]);
+			unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+			goto bail5;
+		}
+		memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
+		memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
+		printk("Finding drives on %s", hba[i]->devname);
+		getgeometry(i);
+		start_fwbk(i); 
+
+		hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
+
+		ida_procinit(i);
+		ida_gendisk[i].major = MAJOR_NR + i;
+		ida_gendisk[i].major_name = "ida";
+		ida_gendisk[i].minor_shift = NWD_SHIFT;
+		ida_gendisk[i].max_p = 16;
+		ida_gendisk[i].max_nr = 16;
+		ida_gendisk[i].init = ida_geninit;
+		ida_gendisk[i].part = ida + (i*256);
+		ida_gendisk[i].sizes = ida_sizes + (i*256);
+		/* ida_gendisk[i].nr_real is handled by getgeometry */
+	
+		blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
+		blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
+		hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
+		read_ahead[MAJOR_NR+i] = READ_AHEAD;
+
+		/* Get on the disk list */
+		ida_gendisk[i].next = gendisk_head;
+		gendisk_head = &ida_gendisk[i];
+
+		init_timer(&hba[i]->timer);
+		hba[i]->timer.expires = jiffies + IDA_TIMER;
+		hba[i]->timer.data = (unsigned long)hba[i];
+		hba[i]->timer.function = ida_timer;
+		add_timer(&hba[i]->timer);
+
+	}
+	/* done ! */
+	return;
+bail5:
+	kfree(ida_hardsizes);
+bail4:
+	kfree(ida_blocksizes);
+bail3:
+	kfree(ida_sizes);
+bail2:
+	kfree(ida);
+bail:
+	printk(KERN_ERR "cpqarray: out of memory.\n");
+}
+
+/*
+ * Find the controller and initialize it
+ *  Cannot use the class code to search, because older array controllers use
+ *    0x018000 and new ones use 0x010400.  So I might as well search for each
+ *    each device IDs, being there are only going to be three of them. 
+ */
+static int cpqarray_pci_detect(void)
+{
+	int index;
+	unchar bus=0, dev_fn=0;
+	
+	/* This seems dumb, surely we could use an array of types to match ?? */
+
+	for(index=0; ; index++) {
+		if (pcibios_find_device(PCI_VENDOR_ID_DEC,
+			 PCI_DEVICE_ID_COMPAQ_42XX, index, &bus, &dev_fn))
+			break;
+		printk(KERN_DEBUG "42XX Device has been found at %x %x\n",
+				bus, dev_fn);
+		if (index == 1000000) break;
+		if (nr_ctlr == 8) {
+			printk("This driver supports a maximum of "
+				"8 controllers.\n");
+			break;
+		}
+		
+		hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+		if(hba[nr_ctlr]==NULL)
+		{
+			printk(KERN_ERR "cpqarray: out of memory.\n");
+			continue;
+		}
+		memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+		if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+			continue;
+		sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+		hba[nr_ctlr]->ctlr = nr_ctlr;
+		nr_ctlr++;
+	}
+
+	for(index=0; ; index++) {
+		unsigned short subvendor=0;
+
+                if (pcibios_find_device(PCI_VENDOR_ID_NCR,
+                         PCI_DEVICE_ID_NCR_53C1510, index, &bus, &dev_fn))
+                        break;
+                printk(KERN_DEBUG "Integrated RAID Chip has been found at %x %x\n",
+                                bus, dev_fn);
+		if(pcibios_read_config_word(bus, dev_fn, 
+			PCI_SUBSYSTEM_VENDOR_ID, &subvendor))	
+		{
+			printk(KERN_DEBUG "cpqarray failed to read subvendor\n");
+			break;
+		}
+		if(subvendor !=  PCI_VENDOR_ID_COMPAQ)
+			break;
+		printk(KERN_DEBUG "Its a compaq RAID Chip\n");
+                if (index == 1000000) break;
+                if (nr_ctlr == 8) {
+                        printk("This driver supports a maximum of "
+                                "8 controllers.\n");
+                        break;
+                }
+
+                hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+                if(hba[nr_ctlr]==NULL)
+                {
+                	printk(KERN_ERR "cpqarray: out of memory.\n");
+                	continue;
+                }
+                memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+                /* DOESNT THIS LEAK MEMORY ?????? - AC */
+                if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+                        continue;
+                sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+                hba[nr_ctlr]->ctlr = nr_ctlr;
+                nr_ctlr++;
+        }
+
+	for(index=0; ; index++) {
+		if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
+			PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
+			break;
+
+		if (index == 1000000) break;
+		if (nr_ctlr == 8) {
+			printk("This driver supports a maximum of "
+				"8 controllers.\n");
+			break;
+		}
+		
+		hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+		if(hba[nr_ctlr]==NULL)
+                {
+                	printk(KERN_ERR "cpqarray: out of memory.\n");
+                	continue;
+                }
+		memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+		if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+			continue;
+		sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+		hba[nr_ctlr]->ctlr = nr_ctlr;
+		nr_ctlr++;
+	}
+
+	return nr_ctlr;
+}
+/*
+ * Find the IO address of the controller, its IRQ and so forth.  Fill
+ * in some basic stuff into the ctlr_info_t structure.
+ */
+static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+{
+	ushort vendor_id, device_id, command;
+	unchar cache_line_size, latency_timer;
+	unchar irq, revision;
+	uint addr[6];
+	__u32 board_id;
+	struct pci_dev *pdev;
+
+	int i;
+
+	pdev = pci_find_slot(bus, device_fn);
+	vendor_id = pdev->vendor;
+	device_id = pdev->device;
+	irq = pdev->irq;
+
+	for(i=0; i<6; i++)
+		addr[i] = pdev->base_address[i];
+
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_COMMAND,&command);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CLASS_REVISION,&revision);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, &cache_line_size);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_LATENCY_TIMER, &latency_timer);
+
+	(void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id);
+
+DBGINFO(
+	printk("vendor_id = %x\n", vendor_id);
+	printk("device_id = %x\n", device_id);
+	printk("command = %x\n", command);
+	for(i=0; i<6; i++)
+		printk("addr[%d] = %x\n", i, addr[i]);
+	printk("revision = %x\n", revision);
+	printk("irq = %x\n", irq);
+	printk("cache_line_size = %x\n", cache_line_size);
+	printk("latency_timer = %x\n", latency_timer);
+	printk("board_id = %x\n", board_id);
+);
+
+	c->intr = irq;
+	c->ioaddr = addr[0] & ~0x1;
+
+	/*
+	 * Memory base addr is first addr with the first bit _not_ set
+	 */
+	for(i=0; i<6; i++)
+		if (!(addr[i] & 0x1)) {
+			c->paddr = addr[i];
+			break;
+		}
+	c->vaddr = remap_pci_mem(c->paddr, 128);
+	c->board_id = board_id;
+
+	for(i=0; i<NR_PRODUCTS; i++) {
+		if (board_id == products[i].board_id) {
+			c->product_name = products[i].product_name;
+			c->access = *(products[i].access);
+			break;
+		}
+	}
+	if (i == NR_PRODUCTS) {
+		printk("Sorry, I don't know how to access the SMART Array"
+			" controller %08lx\n", (unsigned long)board_id);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Map (physical) PCI mem into (virtual) kernel space
+ */
+static ulong remap_pci_mem(ulong base, ulong size)
+{
+        ulong page_base        = ((ulong) base) & PAGE_MASK;
+        ulong page_offs        = ((ulong) base) - page_base;
+        ulong page_remapped    = (ulong) ioremap(page_base, page_offs+size);
+
+        return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
+}
+
+/*
+ * Copy the contents of the ints[] array passed to us by init.
+ */
+void cpqarray_setup(char *str, int *ints)
+{
+	int i;
+	for(i=0; i<ints[0] && i<8; i++)
+		eisa[i] = ints[i+1];
+}
+
+/*
+ * Find an EISA controller's signature.  Set up an hba if we find it.
+ */
+static int cpqarray_eisa_detect(void)
+{
+	int i=0, j;
+	__u32 board_id;
+	int intr;
+
+	while(i<8 && eisa[i]) {
+		if (nr_ctlr == 8) {
+			printk("This driver supports a maximum of "
+				"8 controllers.\n");
+			break;
+		}
+		board_id = inl(eisa[i]+0xC80);
+		for(j=0; j < NR_PRODUCTS; j++)
+			if (board_id == products[j].board_id) 
+				break;
+
+		if (j == NR_PRODUCTS) {
+			printk("Sorry, I don't know how to access the SMART"
+			  " Array controller %08lx\n", (unsigned long)board_id);
+			continue;
+		}
+		hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+		if(hba[nr_ctlr]==NULL)
+		{
+			printk(KERN_ERR "cpqarray: out of memory.\n");
+			continue;
+		}
+		memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+		hba[nr_ctlr]->ioaddr = eisa[i];
+
+		/*
+		 * Read the config register to find our interrupt
+		 */
+		intr = inb(eisa[i]+0xCC0) >> 4;
+		if (intr & 1) intr = 11;
+		else if (intr & 2) intr = 10;
+		else if (intr & 4) intr = 14;
+		else if (intr & 8) intr = 15;
+		
+		hba[nr_ctlr]->intr = intr;
+		sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+		hba[nr_ctlr]->product_name = products[j].product_name;
+		hba[nr_ctlr]->access = *(products[j].access);
+		hba[nr_ctlr]->ctlr = nr_ctlr;
+		hba[nr_ctlr]->board_id = board_id;
+
+DBGINFO(
+	printk("i = %d, j = %d\n", i, j);
+	printk("irq = %x\n", intr);
+	printk("product name = %s\n", products[j].product_name);
+	printk("board_id = %x\n", board_id);
+);
+
+		nr_ctlr++;
+		i++;
+	}
+
+	return nr_ctlr;
+}
+
+
+/*
+ * Open.  Make sure the device is really there.
+ */
+static int ida_open(struct inode *inode, struct file *filep)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+	DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
+		return -ENXIO;
+
+	if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
+						MINOR(inode->i_rdev)] == 0)
+		return -ENXIO;
+
+	/*
+	 * Root is allowed to open raw volume zero even if its not configured
+	 * so array config can still work.  I don't think I really like this,
+	 * but I'm already using way to many device nodes to claim another one
+	 * for "raw controller".
+	 */
+	if (suser()
+		&& ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 
+		&& MINOR(inode->i_rdev) != 0)
+		return -ENXIO;
+
+	hba[ctlr]->drv[dsk].usage_count++;
+	hba[ctlr]->usage_count++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Close.  Sync first.
+ */
+static int ida_release(struct inode *inode, struct file *filep)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+	DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+	fsync_dev(inode->i_rdev);
+
+	hba[ctlr]->drv[dsk].usage_count--;
+	hba[ctlr]->usage_count--;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Enqueuing and dequeuing functions for cmdlists.
+ */
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+	if (*Qptr == NULL) {
+		*Qptr = c;
+		c->next = c->prev = c;
+	} else {
+		c->prev = (*Qptr)->prev;
+		c->next = (*Qptr);
+		(*Qptr)->prev->next = c;
+		(*Qptr)->prev = c;
+	}
+}
+
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+	if (c && c->next != c) {
+		if (*Qptr == c) *Qptr = c->next;
+		c->prev->next = c->next;
+		c->next->prev = c->prev;
+	} else {
+		*Qptr = NULL;
+	}
+	return c;
+}
+
+/*
+ * Get a request and submit it to the controller.
+ * This routine needs to grab all the requests it possibly can from the
+ * req Q and submit them.  Interrupts are off (and need to be off) when you
+ * are in here (either via the dummy do_ida_request functions or by being
+ * called from the interrupt handler
+ */
+static void do_ida_request(int ctlr)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	int seg, sect;
+	char *lastdataend;
+	struct buffer_head *bh;
+	struct request *creq;
+
+	creq = blk_dev[MAJOR_NR+ctlr].current_request;
+	if (creq == NULL || creq->rq_status == RQ_INACTIVE)
+		goto doreq_done;
+
+	if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
+		ctlr > nr_ctlr || h == NULL) {
+		printk("doreq cmd for %d, %x at %p\n",
+				ctlr, creq->rq_dev, creq);
+		complete_buffers(creq->bh, 0);
+		goto doreq_done;
+	}
+
+	if ((c = cmd_alloc(h)) == NULL)
+		goto doreq_done;
+
+	bh = creq->bh;
+
+	c->ctlr = ctlr;
+	c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector;
+	c->bh = bh;
+DBGPX(
+	if (bh == NULL)
+		panic("bh == NULL?");
+	
+	printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
+);
+	seg = 0; lastdataend = NULL;
+	sect = 0;
+	while(bh) {
+		sect += bh->b_size/512;
+DBGPX(
+		if (bh->b_size % 512) {
+			printk("Oh damn.  %d+%d, size = %d\n", creq->sector, sect, bh->b_size);
+			panic("b_size %% 512 != 0");
+		}
+);
+		if (bh->b_data == lastdataend) {
+			c->req.sg[seg-1].size += bh->b_size;
+			lastdataend += bh->b_size;
+		} else {
+			c->req.sg[seg].size = bh->b_size;
+			c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data);
+			lastdataend = bh->b_data + bh->b_size;
+			if (++seg == SG_MAX)
+				break;
+		}
+		bh = bh->b_reqnext;
+	}
+DBGPX(	printk("Submitting %d sectors in %d segments\n", sect, seg); );
+	c->req.hdr.sg_cnt = seg;
+	c->req.hdr.blk_cnt = sect;
+
+	creq->sector += sect;
+	creq->nr_sectors -= sect;
+
+	/* Ready the next request:
+	 * Fix up creq if we still have more buffers in the buffer chain, or
+	 * mark this request as done and ready the next one.
+         */
+	if (creq->nr_sectors) {
+DBGPX(
+		if (bh==NULL) {
+			printk("sector=%d, nr_sectors=%d, sect=%d, seg=%d\n",
+				creq->sector, creq->nr_sectors, sect, seg);
+			panic("mother...");
+		}
+);
+		creq->bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+DBGPX(		printk("More to do on same request %p\n", creq); );
+	} else {
+DBGPX(		printk("Done with %p, queueing %p\n", creq, creq->next); );
+		creq->rq_status = RQ_INACTIVE;
+		blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
+		wake_up(&wait_for_request);
+	}
+
+	c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;
+	c->type = CMD_RWREQ;
+
+	/* Put the request on the tail of the request queue */
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth;
+
+doreq_done:
+	start_io(h);
+}
+
+/* 
+ * start_io submits everything on a controller's request queue
+ * and moves it to the completion queue.
+ *
+ * Interrupts had better be off if you're in here
+ */
+static void start_io(ctlr_info_t *h)
+{
+	cmdlist_t *c;
+
+	while((c = h->reqQ) != NULL) {
+		/* Can't do anything if we're busy */
+		if (h->access.fifo_full(h) == 0)
+			return;
+
+		/* Get the first entry from the request Q */
+		removeQ(&h->reqQ, c);
+		h->Qdepth--;
+	
+		/* Tell the controller to do our bidding */
+		h->access.submit_command(h, c);
+
+		/* Get onto the completion Q */
+		addQ(&h->cmpQ, c);
+	}
+}
+
+static inline void complete_buffers(struct buffer_head *bh, int ok)
+{
+	struct buffer_head *xbh;
+	while(bh) {
+		xbh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		
+		bh->b_end_io(bh, ok);
+
+		bh = xbh;
+	}
+}
+/*
+ * Mark all buffers that cmd was responsible for
+ */
+static inline void complete_command(cmdlist_t *cmd, int timeout)
+{
+	char buf[80];
+	int ok=1;
+
+	if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
+	   (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
+		sprintf(buf, "Non Fatal error on ida/c%dd%d\n",
+				cmd->ctlr, cmd->hdr.unit);
+		console_print(buf);
+		hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
+	}
+	if (cmd->req.hdr.rcode & RCODE_FATAL) {
+		sprintf(buf, "Fatal error on ida/c%dd%d\n",
+				cmd->ctlr, cmd->hdr.unit);
+		console_print(buf);
+		ok = 0;
+	}
+	if (cmd->req.hdr.rcode & RCODE_INVREQ) {
+				sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
+				cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
+				cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
+				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
+		console_print(buf);
+		ok = 0;	
+	}
+	if (timeout) ok = 0;
+	complete_buffers(cmd->bh, ok);
+}
+
+/*
+ *  The controller will interrupt us upon completion of commands.
+ *  Find the command on the completion queue, remove it, tell the OS and
+ *  try to queue up more IO
+ */
+static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ctlr_info_t *h = dev_id;
+	cmdlist_t *c;
+	unsigned long istat;
+	unsigned long flags;
+	__u32 a,a1;
+
+
+	istat = h->access.intr_pending(h);
+	/* Is this interrupt for us? */
+	if (istat == 0)
+		return;
+
+	/*
+	 * If there are completed commands in the completion queue,
+	 * we had better do something about it.
+	 */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (istat & FIFO_NOT_EMPTY) {
+		while((a = h->access.command_completed(h))) {
+			a1 = a; a &= ~3;
+			if ((c = h->cmpQ) == NULL) goto bad_completion;
+			while(c->busaddr != a) {
+				c = c->next;
+				if (c == h->cmpQ) break;
+			}
+			/*
+			 * If we've found the command, take it off the
+			 * completion Q and free it
+			 */
+			if (c->busaddr == a) {
+				removeQ(&h->cmpQ, c);
+				if (c->type == CMD_RWREQ) {
+					complete_command(c, 0);
+					cmd_free(h, c);
+				} else if (c->type == CMD_IOCTL_PEND) {
+					c->type = CMD_IOCTL_DONE;
+				}
+				continue;
+			}
+bad_completion:
+			printk("Completion of %08lx ignored\n", (unsigned long)a1);
+		}
+	}
+
+	/*
+	 * See if we can queue up some more IO
+	 */
+	do_ida_request(h->ctlr);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * This timer was for timing out requests that haven't happened after
+ * IDA_TIMEOUT.  That wasn't such a good idea.  This timer is used to
+ * reset a flags structure so we don't flood the user with
+ * "Non-Fatal error" messages.
+ */
+static void ida_timer(unsigned long tdata)
+{
+	ctlr_info_t *h = (ctlr_info_t*)tdata;
+
+	h->timer.expires = jiffies + IDA_TIMER;
+	add_timer(&h->timer);
+	h->misc_tflags = 0;
+}
+
+/*
+ *  ida_ioctl does some miscellaneous stuff like reporting drive geometry,
+ *  setting readahead and submitting commands from userspace to the controller.
+ */
+static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int error;
+	int diskinfo[4];
+	struct hd_geometry *geo = (struct hd_geometry *)arg;
+	ida_ioctl_t *io = (ida_ioctl_t*)arg;
+	ida_ioctl_t my_io;
+
+	switch(cmd) {
+	case HDIO_GETGEO:
+		if (hba[ctlr]->drv[dsk].cylinders) {
+			diskinfo[0] = hba[ctlr]->drv[dsk].heads;
+			diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
+			diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
+		} else {
+			diskinfo[0] = 0xff;
+			diskinfo[1] = 0x3f;
+			diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f);
+		}
+		put_user(diskinfo[0], &geo->heads);
+		put_user(diskinfo[1], &geo->sectors);
+		put_user(diskinfo[2], &geo->cylinders);
+		put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].start_sect, &geo->start);
+		return 0;
+	case IDAGETDRVINFO:
+		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
+	case BLKGETSIZE:
+		if (!arg) return -EINVAL;
+		put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects, (long*)arg);
+		return 0;
+	case BLKRRPART:
+		return revalidate_logvol(inode->i_rdev, 1);
+	case IDAPASSTHRU:
+		if (!suser()) return -EPERM;
+		error = copy_from_user(&my_io, io, sizeof(my_io));
+		if (error) return error;
+		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
+		if (error) return error;
+		error = copy_to_user(io, &my_io, sizeof(my_io));
+		return error;
+	case IDAGETCTLRSIG:
+		if (!arg) return -EINVAL;
+		put_user(hba[ctlr]->ctlr_sig, (int*)arg);
+		return 0;
+	case IDAREVALIDATEVOLS:
+		return revalidate_allvol(inode->i_rdev);
+	case IDADRIVERVERSION:
+		if (!arg) return -EINVAL;
+		put_user(DRIVER_VERSION, (unsigned long*)arg);
+		return 0;
+
+	case BLKFLSBUF:
+	case BLKROSET:
+	case BLKROGET:
+	case BLKRASET:
+	case BLKRAGET:
+	case BLKPG:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+
+	default:
+		return -EBADRQC;
+	}
+		
+}
+/*
+ * ida_ctlr_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ * however, any elements in the sglist need to be copied to kernel space
+ * or copied back to userspace.
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  Doing an IDA_WRITE_MEDIA and
+ * putting a 64M buffer in the sglist is probably a *bad* idea.
+ */
+static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	void *p = NULL;
+	unsigned long flags;
+	int error;
+
+	if ((c = cmd_alloc(NULL)) == NULL)
+		return -ENOMEM;
+	c->ctlr = ctlr;
+	c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.cmd = io->cmd;
+	c->req.hdr.blk = io->blk;
+	c->req.hdr.blk_cnt = io->blk_cnt;
+	c->type = CMD_IOCTL_PEND;
+
+	/* Pre submit processing */
+	switch(io->cmd) {
+	case PASSTHRU_A:
+		p = kmalloc(io->sg[0].size, GFP_KERNEL);
+		if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+		c->req.bp = virt_to_bus(&(io->c));
+		c->req.sg[0].size = io->sg[0].size;
+		c->req.sg[0].addr = virt_to_bus(p);
+		c->req.hdr.sg_cnt = 1;
+		break;
+	case IDA_READ:
+		p = kmalloc(io->sg[0].size, GFP_KERNEL);
+		if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+		c->req.sg[0].size = io->sg[0].size;
+		c->req.sg[0].addr = virt_to_bus(p);
+		c->req.hdr.sg_cnt = 1;
+		break;
+	case IDA_WRITE:
+	case IDA_WRITE_MEDIA:
+	case DIAG_PASS_THRU:
+		p = kmalloc(io->sg[0].size, GFP_KERNEL);
+		if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+		c->req.sg[0].size = io->sg[0].size;
+		c->req.sg[0].addr = virt_to_bus(p);
+		c->req.hdr.sg_cnt = 1;
+		break;
+	default:
+		c->req.sg[0].size = sizeof(io->c);
+		c->req.sg[0].addr = virt_to_bus(&io->c);
+		c->req.hdr.sg_cnt = 1;
+	}
+
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* Wait for completion */
+	while(c->type != CMD_IOCTL_DONE)
+		schedule();
+
+	/* Post submit processing */
+	switch(io->cmd) {
+	case PASSTHRU_A:
+	case IDA_READ:
+	case DIAG_PASS_THRU:
+		copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
+		/* fall through and free p */
+	case IDA_WRITE:
+	case IDA_WRITE_MEDIA:
+		kfree(p);
+		break;
+	default:
+		/* Nothing to do */
+	}
+
+	io->rcode = c->req.hdr.rcode;
+	error = 0;
+ioctl_err_exit:
+	cmd_free(NULL, c);
+	return error;
+}
+
+/*
+ * Commands are pre-allocated in a large block.  Here we use a simple bitmap
+ * scheme to suballocte them to the driver.  Operations that are not time
+ * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
+ * as the first argument to get a new command.
+ */
+static cmdlist_t * cmd_alloc(ctlr_info_t *h)
+{
+	cmdlist_t * c;
+	int i;
+
+	if (h == NULL) {
+		c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL);
+		if(c==NULL)
+			return NULL;
+	} else {
+		do {
+			i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+			if (i == NR_CMDS)
+				return NULL;
+		} while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+		c = h->cmd_pool + i;
+		h->nr_allocs++;
+	}
+
+	memset(c, 0, sizeof(cmdlist_t));
+	c->busaddr = virt_to_bus(c);
+	return c;
+}
+
+static void cmd_free(ctlr_info_t *h, cmdlist_t *c)
+{
+	int i;
+
+	if (h == NULL) {
+		kfree(c);
+	} else {
+		i = c - h->cmd_pool;
+		clear_bit(i%32, h->cmd_pool_bits+(i/32));
+		h->nr_frees++;
+	}
+}
+
+/***********************************************************************
+    name:        sendcmd
+    Send a command to an IDA using the memory mapped FIFO interface
+    and wait for it to complete.  
+    This routine should only be called at init time.
+***********************************************************************/
+static int sendcmd(
+	__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int blk,
+	unsigned int blkcnt,
+	unsigned int log_unit )
+{
+	cmdlist_t *c;
+	int complete;
+	unsigned long temp;
+	unsigned long i;
+	ctlr_info_t *info_p = hba[ctlr];
+
+	c = cmd_alloc(info_p);
+	c->ctlr = ctlr;
+	c->hdr.unit = log_unit;
+	c->hdr.prio = 0;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	/* The request information. */
+	c->req.hdr.next = 0;
+	c->req.hdr.rcode = 0;
+	c->req.bp = 0;
+	c->req.hdr.sg_cnt = 1;
+	c->req.hdr.reserved = 0;
+	
+	if (size == 0)
+		c->req.sg[0].size = 512;
+	else
+		c->req.sg[0].size = size;
+
+	c->req.hdr.blk = blk;
+	c->req.hdr.blk_cnt = blkcnt;
+	c->req.hdr.cmd = (unsigned char) cmd;
+	c->req.sg[0].addr = (__u32) virt_to_bus(buff);
+	/*
+	 * Disable interrupt
+	 */
+	info_p->access.set_intr_mask(info_p, 0);
+	/* Make sure there is room in the command FIFO */
+	/* Actually it should be completely empty at this time. */
+	for (i = 200000; i > 0; i--) {
+		temp = info_p->access.fifo_full(info_p);
+		if (temp != 0) {
+			break;
+		}
+		udelay(10);
+DBG(
+		printk("ida%d: idaSendPciCmd FIFO full, waiting!\n",
+		       ctlr);
+);
+	} 
+	/*
+	 * Send the cmd
+	 */
+	info_p->access.submit_command(info_p, c);
+	complete = pollcomplete(ctlr);
+	if (complete != 1) {
+		if (complete != c->busaddr) {
+			printk(
+			"ida%d: idaSendPciCmd "
+		      "Invalid command list address returned! (%08lx)\n",
+				ctlr, (unsigned long)complete);
+			cmd_free(info_p, c);
+			return (IO_ERROR);
+		}
+	} else {
+		printk(
+			"ida%d: idaSendPciCmd Timeout out, "
+			"No command list address returned!\n",
+			ctlr);
+		cmd_free(info_p, c);
+		return (IO_ERROR);
+	}
+
+	if (c->req.hdr.rcode & 0x00FE) {
+		if (!(c->req.hdr.rcode & BIG_PROBLEM)) {
+			printk(
+			"ida%d: idaSendPciCmd, error: Controller failed "
+				"at init time "
+				"cmd: 0x%x, return code = 0x%x\n",
+				ctlr, c->req.hdr.cmd, c->req.hdr.rcode);
+
+			cmd_free(info_p, c);
+			return (IO_ERROR);
+		}
+	}
+	cmd_free(info_p, c);
+	return (IO_OK);
+}
+
+static int frevalidate_logvol(kdev_t dev)
+{
+	return revalidate_logvol(dev, 0);
+}
+
+/*
+ * revalidate_allvol is for online array config utilities.  After a
+ * utility reconfigures the drives in the array, it can use this function
+ * (through an ioctl) to make the driver zap any previous disk structs for
+ * that controller and get new ones.
+ *
+ * Right now I'm using the getgeometry() function to do this, but this
+ * function should probably be finer grained and allow you to revalidate one
+ * particualar logical volume (instead of all of them on a particular
+ * controller).
+ */
+static int revalidate_allvol(kdev_t dev)
+{
+	int ctlr, i;
+	unsigned long flags;
+
+	ctlr = MAJOR(dev) - MAJOR_NR;
+	if (MINOR(dev) != 0)
+		return -ENXIO;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hba[ctlr]->usage_count > 1) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		printk("Device busy for volume revalidation (usage=%d)\n",
+					hba[ctlr]->usage_count);
+		return -EBUSY;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	hba[ctlr]->usage_count++;
+
+	/*
+	 * Set the partition and block size structures for all volumes
+	 * on this controller to zero.  We will reread all of this data
+	 */
+	memset(ida+(ctlr*256),            0, sizeof(struct hd_struct)*NWD*16);
+	memset(ida_sizes+(ctlr*256),      0, sizeof(int)*NWD*16);
+	memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16);
+	memset(ida_hardsizes+(ctlr*256),  0, sizeof(int)*NWD*16);
+	memset(hba[ctlr]->drv,            0, sizeof(drv_info_t)*NWD);
+	ida_gendisk[ctlr].nr_real = 0;
+
+	/*
+	 * Tell the array controller not to give us any interupts while
+	 * we check the new geometry.  Then turn interrupts back on when
+	 * we're done.
+	 */
+	hba[ctlr]->access.set_intr_mask(hba[ctlr], 0);
+	getgeometry(ctlr);
+	hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY);
+
+	ida_geninit(&ida_gendisk[ctlr]);
+	for(i=0; i<NWD; i++)
+		if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
+			revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+
+	hba[ctlr]->usage_count--;
+	return 0;
+}
+
+/* Borrowed and adapted from sd.c */
+static int revalidate_logvol(kdev_t dev, int maxusage)
+{
+	int ctlr, target;
+	struct gendisk *gdev;
+	unsigned long flags;
+	int max_p;
+	int start;
+	int i;
+
+	target = DEVICE_NR(dev);
+	ctlr = MAJOR(dev) - MAJOR_NR;
+	gdev = &ida_gendisk[ctlr];
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hba[ctlr]->drv[target].usage_count > maxusage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		printk("Device busy for revalidation (usage=%d)\n",
+					hba[ctlr]->drv[target].usage_count);
+		return -EBUSY;
+	}
+
+	hba[ctlr]->drv[target].usage_count++;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	for(i=max_p; i>=0; i--) {
+		int minor = start+i;
+		kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
+		struct super_block *sb = get_super(devi);
+		sync_dev(devi);
+		if (sb) invalidate_inodes(sb);
+		invalidate_buffers(devi);
+		gdev->part[minor].start_sect = 0;	
+		gdev->part[minor].nr_sects = 0;	
+
+		/* reset the blocksize so we can read the partition table */
+		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+	}
+
+	gdev->part[start].nr_sects =  hba[ctlr]->drv[target].nr_blks;
+	resetup_one_dev(gdev, target);
+	hba[ctlr]->drv[target].usage_count--;
+	return 0;
+}
+
+
+/********************************************************************
+    name: pollcomplete
+    Wait polling for a command to complete.
+    The memory mapped FIFO is polled for the completion.
+    Used only at init time, interrupts disabled.
+ ********************************************************************/
+static int pollcomplete(int ctlr)
+{
+	int done;
+	int i;
+
+	/* Wait (up to 2 seconds) for a command to complete */
+
+	for (i = 200000; i > 0; i--) {
+		done = hba[ctlr]->access.command_completed(hba[ctlr]);
+		if (done == 0) {
+			udelay(10);	/* a short fixed delay */
+		} else
+			return (done);
+	}
+	/* Invalid address to tell caller we ran out of time */
+	return 1;
+}
+/*****************************************************************
+    start_fwbk
+    Starts controller firmwares background processing. 
+    Currently only the Integrated Raid controller needs this done.
+    If the PCI mem address registers are written to after this, 
+	 data corruption may occur
+*****************************************************************/
+static void start_fwbk(int ctlr)
+{
+		id_ctlr_t *id_ctlr_buf; 
+	int ret_code;
+
+	if(	hba[ctlr]->board_id != 0x40400E11)
+	/* Not a Integrated Raid, so there is nothing for us to do */
+		return;
+	printk(KERN_DEBUG "Starting firmware's background processing\n");
+	/* Command does not return anything, but idasend command needs a 
+		buffer */
+	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+	if(id_ctlr_buf==NULL)
+	{
+		printk(KERN_WARNING "Out of memory. Unable to start background processing.\n");
+		return;
+	}		
+	ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, 
+		id_ctlr_buf, 0, 0, 0, 0);
+	if(ret_code != IO_OK)
+		printk(KERN_WARNING "Unable to start background processing\n");
+	kfree(id_ctlr_buf);
+}
+/*****************************************************************
+    getgeometry
+    Get ida logical volume geometry from the controller 
+    This is a large bit of code which once existed in two flavors,
+    It is used only at init time.
+*****************************************************************/
+static void getgeometry(int ctlr)
+{				
+	id_log_drv_t *id_ldrive;
+	id_ctlr_t *id_ctlr_buf;
+	sense_log_drv_stat_t *id_lstatus_buf;
+	config_t *sense_config_buf;
+	unsigned int log_unit, log_index;
+	int ret_code, size;
+	drv_info_t *drv;
+	ctlr_info_t *info_p = hba[ctlr];
+
+	info_p->log_drv_map = 0;	
+	
+	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+	if(id_ldrive == NULL)
+		return;
+	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+	if(id_ctlr_buf == NULL)
+		goto bail2;
+	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+	if(id_lstatus_buf == NULL)
+		goto bail3;
+	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
+	if(sense_config_buf == NULL)
+		goto bail4;
+	memset(id_ldrive, 0, sizeof(id_log_drv_t));
+	memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
+	memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
+	memset(sense_config_buf, 0, sizeof(config_t));
+
+	info_p->phys_drives = 0;
+	info_p->log_drv_map = 0;
+	info_p->drv_assign_map = 0;
+	info_p->drv_spare_map = 0;
+	info_p->mp_failed_drv_map = 0;	/* only initialized here */
+	/* Get controllers info for this logical drive */
+	ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0);
+	if (ret_code == IO_ERROR) {
+		/*
+		 * If can't get controller info, set the logical drive map to 0,
+		 * so the idastubopen will fail on all logical drives
+		 * on the controller.
+		 */
+		goto geo_ret;	/* release the buf and return */
+	}
+	info_p->log_drives = id_ctlr_buf->nr_drvs;;
+	*(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev);
+	info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
+
+	printk(" (%s)\n", info_p->product_name);
+	/*
+	 * Initialize logical drive map to zero
+	 */
+	log_index = 0;
+	/*
+	 * Get drive geometry for all logical drives
+	 */
+	if (id_ctlr_buf->nr_drvs > 16)
+		printk("ida%d:  This driver supports 16 logical drives "
+			"per controller.\n.  Additional drives will not be "
+			"detected\n", ctlr);
+
+	for (log_unit = 0;
+	     (log_index < id_ctlr_buf->nr_drvs)
+	     && (log_unit < NWD);
+	     log_unit++) {
+
+		size = sizeof(sense_log_drv_stat_t);
+
+		/*
+		   Send "Identify logical drive status" cmd
+		 */
+		ret_code = sendcmd(SENSE_LOG_DRV_STAT,
+			     ctlr, id_lstatus_buf, size, 0, 0, log_unit);
+		if (ret_code == IO_ERROR) {
+			/*
+			   If can't get logical drive status, set
+			   the logical drive map to 0, so the
+			   idastubopen will fail for all logical drives
+			   on the controller. 
+			 */
+			info_p->log_drv_map = 0;	
+			printk(
+			     "ida%d: idaGetGeometry - Controller failed "
+				"to report status of logical drive %d\n"
+			 "Access to this controller has been disabled\n",
+				ctlr, log_unit);
+			goto geo_ret;	/* release the buf and return */
+
+		}
+		/*
+		   Make sure the logical drive is configured
+		 */
+		if (id_lstatus_buf->status != LOG_NOT_CONF) {
+			ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive,
+			       sizeof(id_log_drv_t), 0, 0, log_unit);
+			/*
+			   If error, the bit for this
+			   logical drive won't be set and
+			   idastubopen will return error. 
+			 */
+			if (ret_code != IO_ERROR) {
+				drv = &info_p->drv[log_unit];
+				drv->blk_size = id_ldrive->blk_size;
+				drv->nr_blks = id_ldrive->nr_blks;
+				drv->cylinders = id_ldrive->drv.cyl;
+				drv->heads = id_ldrive->drv.heads;
+				drv->sectors = id_ldrive->drv.sect_per_track;
+				info_p->log_drv_map |=	(1 << log_unit);
+
+	printk("ida/c%dd%d: blksz=%d nr_blks=%d\n",
+		ctlr, log_unit, drv->blk_size, drv->nr_blks);
+				ret_code = sendcmd(SENSE_CONFIG,
+						  ctlr, sense_config_buf,
+				 sizeof(config_t), 0, 0, log_unit);
+				if (ret_code == IO_ERROR) {
+					info_p->log_drv_map = 0;
+					goto geo_ret;	/* release the buf and return */
+				}
+				info_p->phys_drives =
+				    sense_config_buf->ctlr_phys_drv;
+				info_p->drv_assign_map
+				    |= sense_config_buf->drv_asgn_map;
+				info_p->drv_assign_map
+				    |= sense_config_buf->spare_asgn_map;
+				info_p->drv_spare_map
+				    |= sense_config_buf->spare_asgn_map;
+			}	/* end of if no error on id_ldrive */
+			log_index = log_index + 1;
+		}		/* end of if logical drive configured */
+	}			/* end of for log_unit */
+geo_ret:
+	kfree(sense_config_buf);
+bail4:	
+	kfree(id_ldrive);
+bail3:
+	kfree(id_lstatus_buf);
+bail2:	
+	kfree(id_ctlr_buf);
+}
diff -u --recursive --new-file v2.3.9/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h
--- v2.3.9/linux/drivers/block/cpqarray.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/cpqarray.h	Tue Jul  6 10:11:40 1999
@@ -0,0 +1,120 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  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.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef CPQARRAY_H
+#define CPQARRAY_H
+
+#ifdef __KERNEL__
+#include <linux/blkdev.h>
+#include <linux/locks.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/md.h>
+#include <linux/timer.h>
+#endif
+
+#include "ida_cmd.h"
+
+#define IO_OK		0
+#define IO_ERROR	1
+#define NWD		16
+#define NWD_SHIFT	4
+
+#define IDA_TIMER	(5*HZ)
+#define IDA_TIMEOUT	(10*HZ)
+
+#define MISC_NONFATAL_WARN	0x01
+
+typedef struct {
+	unsigned blk_size;
+	unsigned nr_blks;
+	unsigned cylinders;
+	unsigned heads;
+	unsigned sectors;
+	int usage_count;
+} drv_info_t;
+
+#ifdef __KERNEL__
+
+struct ctlr_info;
+typedef struct ctlr_info ctlr_info_t;
+
+struct access_method {
+	void (*submit_command)(ctlr_info_t *h, cmdlist_t *c);
+	void (*set_intr_mask)(ctlr_info_t *h, unsigned long val);
+	unsigned long (*fifo_full)(ctlr_info_t *h);
+	unsigned long (*intr_pending)(ctlr_info_t *h);
+	unsigned long (*command_completed)(ctlr_info_t *h);
+};
+
+struct board_type {
+	__u32	board_id;
+	char	*product_name;
+	struct access_method *access;
+};
+
+struct ctlr_info {
+	int	ctlr;
+	char	devname[8];
+	__u32	log_drv_map;
+	__u32	drv_assign_map;
+	__u32	drv_spare_map;
+	__u32	mp_failed_drv_map;
+
+	char	firm_rev[4];
+	int	ctlr_sig;
+
+	int	log_drives;
+	int	phys_drives;
+
+	__u32	board_id;
+	char	*product_name;	
+
+	__u32	vaddr;
+	__u32	paddr;
+	__u32	ioaddr;
+	int	intr;
+	int	usage_count;
+	drv_info_t	drv[NWD];
+	struct proc_dir_entry *proc;
+
+	struct access_method access;
+
+	cmdlist_t *reqQ;
+	cmdlist_t *cmpQ;
+	cmdlist_t *cmd_pool;
+	__u32	*cmd_pool_bits;
+
+	unsigned int Qdepth;
+	unsigned int maxQsinceinit;
+
+	unsigned int nr_requests;
+	unsigned int nr_allocs;
+	unsigned int nr_frees;
+	struct timer_list timer;
+	unsigned int misc_tflags;
+};
+#endif
+
+#endif /* CPQARRAY_H */
diff -u --recursive --new-file v2.3.9/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.9/linux/drivers/block/floppy.c	Wed Jun  9 16:42:58 1999
+++ linux/drivers/block/floppy.c	Tue Jul  6 19:05:48 1999
@@ -3896,7 +3896,7 @@
 
 /* Determine the floppy disk controller type */
 /* This routine was written by David C. Niemi */
-__initfunc(static char get_fdc_version(void))
+static char __init get_fdc_version(void)
 {
 	int r;
 
@@ -3974,7 +3974,7 @@
 
 /* lilo configuration */
 
-__initfunc(static void floppy_set_flags(int *ints,int param, int param2))
+static void __init floppy_set_flags(int *ints,int param, int param2)
 {
 	int i;
 
@@ -3987,7 +3987,7 @@
 	DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
 }
 
-__initfunc(static void daring(int *ints,int param, int param2))
+static void __init daring(int *ints,int param, int param2)
 {
 	int i;
 
@@ -4003,7 +4003,7 @@
 	DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
 }
 
-__initfunc(static void set_cmos(int *ints, int dummy, int dummy2))
+static void __init set_cmos(int *ints, int dummy, int dummy2)
 {
 	int current_drive=0;
 
@@ -4063,7 +4063,7 @@
 	{ "L40SX", 0, &print_unex, 0, 0 } };
 
 #define FLOPPY_SETUP
-__initfunc(void floppy_setup(char *str, int *ints))
+void __init floppy_setup(char *str, int *ints)
 {
 	int i;
 	int param;
@@ -4101,7 +4101,7 @@
 static int have_no_fdc= -EIO;
 
 
-__initfunc(int floppy_init(void))
+int __init floppy_init(void)
 {
 	int i,unit,drive;
 
@@ -4362,7 +4362,7 @@
 
 char *floppy=NULL;
 
-__initfunc(static void parse_floppy_cfg_string(char *cfg))
+static void __init parse_floppy_cfg_string(char *cfg)
 {
 	char *ptr;
 	int ints[11];
@@ -4378,7 +4378,7 @@
 	}
 }
 
-__initfunc(static void mod_setup(char *pattern, void (*setup)(char *, int *)))
+static void __init mod_setup(char *pattern, void (*setup)(char *, int *))
 {
 	unsigned long i;
 	char c;
diff -u --recursive --new-file v2.3.9/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.3.9/linux/drivers/block/genhd.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/genhd.c	Mon Jul  5 20:35:18 1999
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 
 #include <asm/system.h>
+#include <asm/byteorder.h>
 
 /*
  * Many architectures don't like unaligned accesses, which is
@@ -60,6 +61,7 @@
 extern int blk_dev_init(void);
 extern int scsi_dev_init(void);
 extern int net_dev_init(void);
+extern int i2o_init(void);
 
 #ifdef CONFIG_PPC
 extern void note_bootable_part(kdev_t dev, int part);
@@ -112,6 +114,16 @@
 			return buf;
 		}
 	}
+	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+		int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+ 		int disk = minor >> hd->minor_shift;
+ 		int part = minor & (( 1 << hd->minor_shift) - 1);
+ 		if (part == 0)
+ 			sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+ 		else
+ 			sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+ 		return buf;
+ 	}
 	if (part)
 		sprintf(buf, "%s%c%d", maj, unit, part);
 	else
@@ -121,10 +133,13 @@
 
 static void add_partition (struct gendisk *hd, int minor, int start, int size)
 {
-	char buf[32];
+	char buf[40];
 	hd->part[minor].start_sect = start;
 	hd->part[minor].nr_sects   = size;
-	printk(" %s", disk_name(hd, minor, buf));
+	if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7)
+		printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+	else
+		printk(" %s", disk_name(hd, minor, buf));
 }
 
 static inline int is_extended_partition(struct partition *p)
@@ -222,7 +237,7 @@
 		if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
 			return;
 
-		if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
+		if ((*(__u16 *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
 			goto done;
 
 		p = (struct partition *) (0x1BE + bh->b_data);
@@ -676,12 +691,10 @@
 	label = (struct disklabel *) (bh->b_data+64);
 	partition = label->d_partitions;
 	if (label->d_magic != DISKLABELMAGIC) {
-		printk("magic: %08x\n", label->d_magic);
 		brelse(bh);
 		return 0;
 	}
 	if (label->d_magic2 != DISKLABELMAGIC) {
-		printk("magic2: %08x\n", label->d_magic2);
 		brelse(bh);
 		return 0;
 	}
@@ -775,14 +788,11 @@
 #endif /* CONFIG_SUN_PARTITION */
 
 #ifdef CONFIG_SGI_PARTITION
-#include <asm/byteorder.h>
 
 static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
-	int i, csum;
-	unsigned int *ui;
-	unsigned int start, blocks, cs;
-	int magic;
+	int i, csum, magic;
+	unsigned int *ui, start, blocks, cs;
 	struct buffer_head *bh;
 	struct sgi_disklabel {
 		int magic_mushroom;         /* Big fat spliff... */
@@ -851,7 +861,6 @@
 #endif
 
 #ifdef CONFIG_AMIGA_PARTITION
-#include <asm/byteorder.h>
 #include <linux/affs_hardblocks.h>
 
 static __inline__ u32
@@ -919,13 +928,14 @@
 				blk = htonl(pb->pb_Next);
 				if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block(
 				    (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
-					
+
 					/* Tell Kernel about it */
 
 					if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 -
 							  htonl(pb->pb_Environment[9])) *
 							 htonl(pb->pb_Environment[3]) *
 							 htonl(pb->pb_Environment[5]))) {
+						brelse(bh);
 						continue;
 					}
 					start_sect = htonl(pb->pb_Environment[9]) *
@@ -938,8 +948,9 @@
 				brelse(bh);
 			}
 			printk("\n");
-			break;
 		}
+		else
+			brelse(bh);
 	}
 
 rdb_done:
@@ -1077,7 +1088,7 @@
 #endif /* CONFIG_MAC_PARTITION */
 
 #ifdef CONFIG_ATARI_PARTITION
-#include <asm/atari_rootsec.h>
+#include <linux/atari_rootsec.h>
 
 /* ++guenther: this should be settable by the user ("make config")?.
  */
@@ -1091,16 +1102,27 @@
   struct rootsector *rs;
   struct partition_info *pi;
   ulong extensect;
+  unsigned int psum;
+  int i;
 #ifdef ICD_PARTS
   int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
 #endif
 
   bh = bread (dev, 0, get_ptable_blocksize(dev));
-  if (!bh)
-    {
-      printk (" unable to read block 0\n");
+  if (!bh) {
+      printk (" unable to read block 0 (partition table)\n");
       return -1;
-    }
+  }
+
+  /* Verify this is an Atari rootsector: */
+  psum=0;
+  for (i=0;i<256;i++) {
+    psum+=ntohs(((__u16 *) (bh->b_data))[i]);
+  }
+  if ((psum & 0xFFFF) != 0x1234) {
+    brelse(bh);
+    return 0;
+  }
 
   rs = (struct rootsector *) bh->b_data;
   pi = &rs->part[0];
@@ -1121,7 +1143,7 @@
 	      part_fmt = 1;
 #endif
 	      printk(" XGM<");
-	      partsect = extensect = pi->st;
+	      partsect = extensect = ntohl(pi->st);
 	      while (1)
 		{
 		  xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev));
@@ -1142,8 +1164,8 @@
 		    break;
 		  }
 
-		  add_partition(hd, minor, partsect + xrs->part[0].st,
-				xrs->part[0].siz);
+		  add_partition(hd, minor, partsect + ntohl(xrs->part[0].st),
+				ntohl(xrs->part[0].siz));
 
 		  if (!(xrs->part[1].flg & 1)) {
 		    /* end of linked partition list */
@@ -1156,7 +1178,7 @@
 		    break;
 		  }
 
-		  partsect = xrs->part[1].st + extensect;
+		  partsect = ntohl(xrs->part[1].st) + extensect;
 		  brelse (xbh);
 		  minor++;
 		  if (minor >= m_lim) {
@@ -1169,7 +1191,7 @@
 	  else
 	    {
 	      /* we don't care about other id's */
-	      add_partition (hd, minor, pi->st, pi->siz);
+	      add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz));
 	    }
 	}
     }
@@ -1196,7 +1218,7 @@
              memcmp (pi->id, "RAW", 3) == 0) )
         {
           part_fmt = 2;
-	  add_partition (hd, minor, pi->st, pi->siz);
+	  add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz));
         }
       }
       printk(" >");
@@ -1211,14 +1233,62 @@
 }
 #endif /* CONFIG_ATARI_PARTITION */
 
+#ifdef CONFIG_ULTRIX_PARTITION
+
+static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
+{
+	int i, minor = current_minor;
+	struct buffer_head *bh;
+	struct ultrix_disklabel {
+		s32	pt_magic;	/* magic no. indicating part. info exits */
+		s32	pt_valid;	/* set by driver if pt is current */
+		struct  pt_info {
+			s32		pi_nblocks; /* no. of sectors */
+			u32		pi_blkoff;  /* block offset for start */
+		} pt_part[8];
+	} *label;
+
+#define PT_MAGIC	0x032957	/* Partition magic number */
+#define PT_VALID	1		/* Indicates if struct is valid */
+
+#define	SBLOCK	((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \
+                  /get_ptable_blocksize(dev)))
+
+	bh = bread (dev, SBLOCK, get_ptable_blocksize(dev));
+	if (!bh) {
+		printk (" unable to read block 0x%lx\n", SBLOCK);
+		return -1;
+	}
+	
+	label = (struct ultrix_disklabel *)(bh->b_data
+                                            + get_ptable_blocksize(dev)
+                                            - sizeof(struct ultrix_disklabel));
+
+	if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
+		for (i=0; i<8; i++, minor++)
+			if (label->pt_part[i].pi_nblocks)
+				add_partition(hd, minor, 
+					      label->pt_part[i].pi_blkoff,
+					      label->pt_part[i].pi_nblocks);
+		brelse(bh);
+		printk ("\n");
+		return 1;
+	} else {
+		brelse(bh);
+		return 0;
+	}
+}
+
+#endif /* CONFIG_ULTRIX_PARTITION */
+
 static void check_partition(struct gendisk *hd, kdev_t dev)
 {
 	static int first_time = 1;
 	unsigned long first_sector;
-	char buf[32];
+	char buf[40];
 
 	if (first_time)
-		printk("Partition check:\n");
+		printk(KERN_INFO "Partition check:\n");
 	first_time = 0;
 	first_sector = hd->part[MINOR(dev)].start_sect;
 
@@ -1231,7 +1301,7 @@
 		return;
 	}
 
-	printk(" %s:", disk_name(hd, MINOR(dev), buf));
+	printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
 #ifdef CONFIG_MSDOS_PARTITION
 	if (msdos_partition(hd, dev, first_sector))
 		return;
@@ -1260,6 +1330,10 @@
 	if(sgi_partition(hd, dev, first_sector))
 		return;
 #endif
+#ifdef CONFIG_ULTRIX_PARTITION
+	if(ultrix_partition(hd, dev, first_sector))
+		return;
+#endif
 	printk(" unknown partition table\n");
 }
 
@@ -1309,9 +1383,10 @@
 		resetup_one_dev(dev, drive);
 }
 
-__initfunc(void device_setup(void))
+void __init device_setup(void)
 {
 	extern void console_map_init(void);
+	extern void cpqarray_init(void);
 #ifdef CONFIG_PARPORT
 	extern int parport_init(void) __init;
 #endif
@@ -1326,6 +1401,13 @@
 #ifdef CONFIG_PARPORT
 	parport_init();
 #endif
+	/*
+	 *	I2O must come before block and char as the I2O layer may
+	 *	in future claim devices that block/char most not touch.
+	 */
+#ifdef CONFIG_I2O
+	i2o_init();
+#endif
 	chr_dev_init();
 	blk_dev_init();
 	sti();
@@ -1336,6 +1418,9 @@
 #ifdef CONFIG_SCSI
 	scsi_dev_init();
 #endif
+#ifdef CONFIG_BLK_CPQ_DA
+	cpqarray_init();
+#endif
 #ifdef CONFIG_INET
 	net_dev_init();
 #endif
@@ -1362,7 +1447,7 @@
 int get_partition_list(char * page)
 {
 	struct gendisk *p;
-	char buf[32];
+	char buf[40];
 	int n, len;
 
 	len = sprintf(page, "major minor  #blocks  name\n\n");
diff -u --recursive --new-file v2.3.9/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v2.3.9/linux/drivers/block/hd.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/hd.c	Tue Jul  6 19:05:48 1999
@@ -113,7 +113,7 @@
 }
 #endif
 
-__initfunc(void hd_setup(char *str, int *ints))
+void __init hd_setup(char *str, int *ints)
 {
 	int hdind = 0;
 
@@ -783,7 +783,7 @@
 	block_fsync		/* fsync */
 };
 
-__initfunc(int hd_init(void))
+int __init hd_init(void)
 {
 	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
 		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
diff -u --recursive --new-file v2.3.9/linux/drivers/block/hpt343.c linux/drivers/block/hpt343.c
--- v2.3.9/linux/drivers/block/hpt343.c	Wed May 26 16:55:40 1999
+++ linux/drivers/block/hpt343.c	Wed Dec 31 16:00:00 1969
@@ -1,392 +0,0 @@
-/*
- * linux/drivers/block/hpt343.c		Version 0.23	May 12, 1999
- *
- * Copyright (C) 1998-99	Andre Hedrick
- *					(hedrick@astro.dyer.vanderbilt.edu)
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
- *
- * drive_number
- *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- */
-
-#include <linux/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"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define HPT343_DEBUG_DRIVE_INFO		0
-#define HPT343_DISABLE_ALL_DMAING	0
-#define HPT343_DMA_DISK_ONLY		0
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static void hpt343_clear_chipset (ide_drive_t *drive)
-{
-	int drive_number	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
-	tmp2 = ((0x00 << drive_number) | reg2);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-}
-
-static int hpt343_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int			err;
-	byte			hi_speed, lo_speed;
-	int drive_number	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	SPLIT_BYTE(speed, hi_speed, lo_speed);
-
-	if (hi_speed & 7) {
-		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
-	} else {
-		lo_speed <<= 5;
-		lo_speed >>= 5;
-	}
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
-	tmp2 = ((hi_speed << drive_number) | reg2);
-	err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-
-#if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
-		drive_number, reg1, tmp1, reg2, tmp2,
-		hi_speed, lo_speed, err);
-#endif /* HPT343_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
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-
-#if HPT343_DISABLE_ALL_DMAING
-	return ((int) ide_dma_off);
-#elif HPT343_DMA_DISK_ONLY
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-#endif /* HPT343_DISABLE_ALL_DMAING */
-
-	if (id->dma_ultra & 0x0004) {
-		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0x0F00;
-			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) {
-		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0x0F00;
-			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) {
-		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0x0F00;
-			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) {
-		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);
-	}
-
-	(void) hpt343_tune_chipset(drive, speed);
-
-	return ((int)	((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 : 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) hpt343_tune_chipset(drive, speed);
-}
-
-#if 0
-static void hpt343_tune_drive (ide_drive_t *drive, byte pio)
-{
-}
-#endif
-
-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 & 0x0007) {
-				/* 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);
-}
-
-/*
- * hpt343_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 hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			hpt343_clear_chipset(drive);
-			return config_drive_xfer_rate(drive);
-#if 0
-		case ide_dma_off:
-		case ide_dma_off_quietly:
-		case ide_dma_on:
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_read:
-		case ide_dma_write:
-		case ide_dma_begin:
-		case ide_dma_end:
-		case ide_dma_test_irq:
-#endif
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define	HPT343_PCI_INIT_REG		0x80
-
-__initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name))
-{
-	int i;
-	unsigned short cmd;
-	unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
-#if 0
-	unsigned char misc10 = inb(hpt343IoBase + 0x0010);
-	unsigned char misc11 = inb(hpt343IoBase + 0x0011);
-#endif
-
-	pci_write_config_byte(dev, HPT343_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] = (hpt343IoBase + 0x20);
-	dev->base_address[1] = (hpt343IoBase + 0x34);
-	dev->base_address[2] = (hpt343IoBase + 0x28);
-	dev->base_address[3] = (hpt343IoBase + 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, (hpt343IoBase + 0x0010));
-	outb(misc11, (hpt343IoBase + 0x0011));
-#endif
-
-#ifdef DEBUG
-	printk("%s: 0x%02x 0x%02x\n",
-		(pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name,
-		inb(hpt343IoBase + 0x0010),
-		inb(hpt343IoBase + 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);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
-		}
-	} else {
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-	}
-	return dev->irq;
-}
-
-__initfunc(void ide_init_hpt343 (ide_hwif_t *hwif))
-{
-	if (hwif->dma_base) {
-		unsigned short pcicmd = 0;
-
-		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-		hwif->dmaproc = &hpt343_dmaproc;
-	}
-}
diff -u --recursive --new-file v2.3.9/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c
--- v2.3.9/linux/drivers/block/hpt34x.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/hpt34x.c	Mon Jul  5 20:13:59 1999
@@ -0,0 +1,408 @@
+/*
+ * linux/drivers/block/hpt34x.c		Version 0.24	July 3, 1999
+ *
+ * Copyright (C) 1998-99	Andre Hedrick
+ *					(hedrick@astro.dyer.vanderbilt.edu)
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * drive_number
+ *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ */
+
+#include <linux/config.h>
+#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"
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define HPT343_DEBUG_DRIVE_INFO		0
+#define HPT343_DISABLE_ALL_DMAING	0
+#define HPT343_DMA_DISK_ONLY		0
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+	int drive_number	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+	unsigned int reg1	= 0, tmp1 = 0;
+	unsigned int reg2	= 0, tmp2 = 0;
+
+	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+	tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
+	tmp2 = ((0x00 << drive_number) | reg2);
+	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	int			err;
+	byte			hi_speed, lo_speed;
+	int drive_number	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+	unsigned int reg1	= 0, tmp1 = 0;
+	unsigned int reg2	= 0, tmp2 = 0;
+
+	SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+	if (hi_speed & 7) {
+		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+	} else {
+		lo_speed <<= 5;
+		lo_speed >>= 5;
+	}
+
+	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+	tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
+	tmp2 = ((hi_speed << drive_number) | reg2);
+	err = ide_config_drive_speed(drive, speed);
+	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+		" (0x%02x 0x%02x) 0x%04x\n",
+		drive->name, ide_xfer_verbose(speed),
+		drive_number, reg1, tmp1, reg2, tmp2,
+		hi_speed, lo_speed, err);
+#endif /* HPT343_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
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte speed		= 0x00;
+
+#if HPT343_DISABLE_ALL_DMAING
+	return ((int) ide_dma_off);
+#elif HPT343_DMA_DISK_ONLY
+	if (drive->media != ide_disk)
+		return ((int) ide_dma_off_quietly);
+#endif /* HPT343_DISABLE_ALL_DMAING */
+
+	if (id->dma_ultra & 0x0004) {
+		if (!((id->dma_ultra >> 8) & 4)) {
+			drive->id->dma_ultra &= ~0x0F00;
+			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) {
+		if (!((id->dma_ultra >> 8) & 2)) {
+			drive->id->dma_ultra &= ~0x0F00;
+			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) {
+		if (!((id->dma_ultra >> 8) & 1)) {
+			drive->id->dma_ultra &= ~0x0F00;
+			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) {
+		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);
+	}
+
+	(void) hpt34x_tune_chipset(drive, speed);
+
+	return ((int)	((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 : 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) hpt34x_tune_chipset(drive, speed);
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
+{
+	byte speed;
+
+	hpt34x_clear_chipset(drive);
+	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) hpt34x_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 & 0x0007) {
+				/* 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 hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			hpt34x_clear_chipset(drive);
+			return config_drive_xfer_rate(drive);
+#if 0
+		case ide_dma_off:
+		case ide_dma_off_quietly:
+		case ide_dma_on:
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_read:
+		case ide_dma_write:
+		case ide_dma_begin:
+		case ide_dma_end:
+		case ide_dma_test_irq:
+#endif
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define	HPT34X_PCI_INIT_REG		0x80
+
+__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);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
+		}
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+	} else {
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+	}
+	return dev->irq;
+}
+
+__initfunc(void ide_init_hpt34x (ide_hwif_t *hwif))
+{
+	hwif->tuneproc = &hpt34x_tune_drive;
+	if (hwif->dma_base) {
+		unsigned short pcicmd = 0;
+
+		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+#ifdef CONFIG_BLK_DEV_HPT34X_DMA
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+#endif /* CONFIG_BLK_DEV_HPT34X_DMA */
+		hwif->dmaproc = &hpt34x_dmaproc;
+	} else {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
+}
diff -u --recursive --new-file v2.3.9/linux/drivers/block/icside.c linux/drivers/block/icside.c
--- v2.3.9/linux/drivers/block/icside.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/icside.c	Thu Jul  1 10:25:38 1999
@@ -299,6 +299,9 @@
 		drive->drive_data = 250;
 	}
 
+#if 1
+	err = ide_config_drive_speed(drive, (byte) speed);
+#else
 	/*
 	 * Don't use ide_wait_cmd here - it will
 	 * attempt to set_geometry and recalibrate,
@@ -313,6 +316,7 @@
 
 	err = ide_wait_stat(drive, DRIVE_READY,
 			    BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+#endif
 
 	if (err == 0) {
 		drive->id->dma_mword &= 0x00ff;
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ida_cmd.h linux/drivers/block/ida_cmd.h
--- v2.3.9/linux/drivers/block/ida_cmd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ida_cmd.h	Mon Jul  5 19:52:13 1999
@@ -0,0 +1,347 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  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.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef ARRAYCMD_H
+#define ARRAYCMD_H
+
+#include <asm/types.h>
+#if 0
+#include <linux/blkdev.h>
+#endif
+
+/* for the Smart Array 42XX cards */
+#define S42XX_REQUEST_PORT_OFFSET	0x40
+#define S42XX_REPLY_INTR_MASK_OFFSET	0x34
+#define S42XX_REPLY_PORT_OFFSET		0x44
+#define S42XX_INTR_STATUS		0x30
+
+#define S42XX_INTR_OFF		0x08
+#define S42XX_INTR_PENDING	0x08
+
+#define COMMAND_FIFO		0x04
+#define COMMAND_COMPLETE_FIFO	0x08
+#define INTR_MASK		0x0C
+#define INTR_STATUS		0x10
+#define INTR_PENDING		0x14
+
+#define FIFO_NOT_EMPTY		0x01
+#define FIFO_NOT_FULL		0x02
+
+#define BIG_PROBLEM		0x40
+#define LOG_NOT_CONF		2
+
+#pragma pack(1)
+typedef struct {
+	__u32	size;
+	__u32	addr;
+} sg_t;
+
+#define RCODE_NONFATAL	0x02
+#define RCODE_FATAL	0x04
+#define RCODE_INVREQ	0x10
+typedef struct {
+	__u16	next;
+	__u8	cmd;
+	__u8	rcode;
+	__u32	blk;
+	__u16	blk_cnt;
+	__u8	sg_cnt;
+	__u8	reserved;
+} rhdr_t;
+
+#define SG_MAX			32
+typedef struct {
+	rhdr_t	hdr;
+	sg_t	sg[SG_MAX];
+	__u32	bp;
+} rblk_t;
+
+typedef struct {
+	__u8	unit;
+	__u8	prio;
+	__u16	size;
+} chdr_t;
+
+#define CMD_RWREQ	0x00
+#define CMD_IOCTL_PEND	0x01
+#define CMD_IOCTL_DONE	0x02
+
+typedef struct cmdlist {
+	chdr_t	hdr;
+	rblk_t	req;
+	__u32	size;
+	int	retry_cnt;
+	__u32	busaddr;
+	int	ctlr;
+	struct cmdlist *prev;
+	struct cmdlist *next;
+	struct buffer_head *bh;
+	int type;
+} cmdlist_t;
+	
+#define ID_CTLR		0x11
+typedef struct {
+	__u8	nr_drvs;
+	__u32	cfg_sig;
+	__u8	firm_rev[4];
+	__u8	rom_rev[4];
+	__u8	hw_rev;
+	__u32	bb_rev;
+	__u32	drv_present_map;
+	__u32	ext_drv_map;
+	__u32	board_id;
+	__u8	cfg_error;
+	__u32	non_disk_bits;
+	__u8	bad_ram_addr;
+	__u8	cpu_rev;
+	__u8	pdpi_rev;
+	__u8	epic_rev;
+	__u8	wcxc_rev;
+	__u8	marketing_rev;
+	__u8	ctlr_flags;
+	__u8	host_flags;
+	__u8	expand_dis;
+	__u8	scsi_chips;
+	__u32	max_req_blocks;
+	__u32	ctlr_clock;
+	__u8	drvs_per_bus;
+	__u16	big_drv_present_map[8];
+	__u16	big_ext_drv_map[8];
+	__u16	big_non_disk_map[8];
+	__u16	task_flags;
+	__u8	icl_bus;
+	__u8	red_modes;
+	__u8	cur_red_mode;
+	__u8	red_ctlr_stat;
+	__u8	red_fail_reason;
+	__u8	reserved[403];
+} id_ctlr_t;
+
+typedef struct {
+	__u16	cyl;
+	__u8	heads;
+	__u8	xsig;
+	__u8	psectors;
+	__u16	wpre;
+	__u8	maxecc;
+	__u8	drv_ctrl;
+	__u16	pcyls;
+	__u8	pheads;
+	__u16	landz;
+	__u8	sect_per_track;
+	__u8	cksum;
+} drv_param_t;
+
+#define ID_LOG_DRV	0x10
+typedef struct {
+	__u16	blk_size;
+	__u32	nr_blks;
+	drv_param_t drv;
+	__u8	fault_tol;
+	__u8	reserved;
+	__u8	bios_disable;
+} id_log_drv_t;
+
+#define ID_LOG_DRV_EXT	0x18
+typedef struct {
+	__u32	log_drv_id;
+	__u8	log_drv_label[64];
+	__u8	reserved[418];
+} id_log_drv_ext_t;
+
+#define SENSE_LOG_DRV_STAT	0x12
+typedef struct {
+	__u8	status;
+	__u32	fail_map;
+	__u16	read_err[32];
+	__u16	write_err[32];
+	__u8	drv_err_data[256];
+	__u8	drq_timeout[32];
+	__u32	blks_to_recover;
+	__u8	drv_recovering;
+	__u16	remap_cnt[32];
+	__u32	replace_drv_map;
+	__u32	act_spare_map;
+	__u8	spare_stat;
+	__u8	spare_repl_map[32];
+	__u32	repl_ok_map;
+	__u8	media_exch;
+	__u8	cache_fail;
+	__u8	expn_fail;
+	__u8	unit_flags;
+	__u16	big_fail_map[8];
+	__u16	big_remap_map[8];
+	__u16	big_repl_map[8];
+	__u16	big_act_spare_map[8];
+	__u8	big_spar_repl_map[128];
+	__u16	big_repl_ok_map[8];
+	__u8	big_drv_rebuild;
+	__u8	reserved[36];
+} sense_log_drv_stat_t;
+
+#define START_RECOVER		0x13
+
+#define ID_PHYS_DRV		0x15
+typedef struct {
+	__u8	scsi_bus;
+	__u8	scsi_id;
+	__u16	blk_size;
+	__u32	nr_blks;
+	__u32	rsvd_blks;
+	__u8	drv_model[40];
+	__u8	drv_sn[40];
+	__u8	drv_fw[8];
+	__u8	scsi_iq_bits;
+	__u8	compaq_drv_stmp;
+	__u8	last_fail;
+	__u8	phys_drv_flags;
+	__u8	phys_drv_flags1;
+	__u8	scsi_lun;
+	__u8	phys_drv_flags2;
+	__u8	reserved;
+	__u32	spi_speed_rules;
+	__u8	phys_connector[2];
+	__u8	phys_box_on_bus;
+	__u8	phys_bay_in_box;
+} id_phys_drv_t;
+
+#define BLINK_DRV_LEDS		0x16
+typedef struct {
+	__u32	blink_duration;
+	__u32	reserved;
+	__u8	blink[256];
+	__u8	reserved1[248];
+} blink_drv_leds_t;
+
+#define SENSE_BLINK_LEDS	0x17
+typedef struct {
+	__u32	blink_duration;
+	__u32	btime_elap;
+	__u8	blink[256];
+	__u8	reserved1[248];
+} sense_blink_leds_t;
+
+#define IDA_READ		0x20
+#define IDA_WRITE		0x30
+#define IDA_WRITE_MEDIA		0x31
+#define RESET_TO_DIAG		0x40
+#define DIAG_PASS_THRU		0x41
+
+#define SENSE_CONFIG		0x50
+#define SET_CONFIG		0x51
+typedef struct {
+	__u32	cfg_sig;
+	__u16	compat_port;
+	__u8	data_dist_mode;
+	__u8	surf_an_ctrl;
+	__u16	ctlr_phys_drv;
+	__u16	log_unit_phys_drv;
+	__u16	fault_tol_mode;
+	__u8	phys_drv_param[16];
+	drv_param_t drv;
+	__u32	drv_asgn_map;
+	__u16	dist_factor;
+	__u32	spare_asgn_map;
+	__u8	reserved[6];
+	__u16	os;
+	__u8	ctlr_order;
+	__u8	extra_info;
+	__u32	data_offs;
+	__u8	parity_backedout_write_drvs;
+	__u8	parity_dist_mode;
+	__u8	parity_shift_fact;
+	__u8	bios_disable_flag;
+	__u32	blks_on_vol;
+	__u32	blks_per_drv;
+	__u8	scratch[16];
+	__u16	big_drv_map[8];
+	__u16	big_spare_map[8];
+	__u8	ss_source_vol;
+	__u8	mix_drv_cap_range;
+	struct {
+		__u16	big_drv_map[8];
+		__u32	blks_per_drv;
+		__u16	fault_tol_mode;
+		__u16	dist_factor;
+	} MDC_range[4];
+	__u8	reserved1[248];
+} config_t;
+
+#define BYPASS_VOL_STATE	0x52
+#define SS_CREATE_VOL		0x53
+#define CHANGE_CONFIG		0x54
+#define SENSE_ORIG_CONF		0x55
+#define REORDER_LOG_DRV		0x56
+typedef struct {
+	__u8	old_units[32];
+} reorder_log_drv_t;
+
+#define LABEL_LOG_DRV		0x57
+typedef struct {
+	__u8	log_drv_label[64];
+} label_log_drv_t;
+
+#define SS_TO_VOL		0x58
+	
+#define SET_SURF_DELAY		0x60
+typedef struct {
+	__u16	delay;
+	__u8	reserved[510];
+} surf_delay_t;
+
+#define SET_OVERHEAT_DELAY	0x61
+typedef struct {
+	__u16	delay;
+} overhead_delay_t;
+ 
+#define SET_MP_DELAY
+typedef struct {
+	__u16	delay;
+	__u8	reserved[510];
+} mp_delay_t;
+
+#define PASSTHRU_A	0x91
+typedef struct {
+	__u8	target;
+	__u8	bus;
+	__u8	lun;
+	__u32	timeout;
+	__u32	flags;
+	__u8	status;
+	__u8	error;
+	__u8	cdb_len;
+	__u8	sense_error;
+	__u8	sense_key;
+	__u32	sense_info;
+	__u8	sense_code;
+	__u8	sense_qual;
+	__u8	residual;
+	__u8	reserved[4];
+	__u8	cdb[12];	
+} scsi_param_t;
+
+#define RESUME_BACKGROUND_ACTIVITY	0x99
+#pragma pack()	
+
+#endif /* ARRAYCMD_H */
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h
--- v2.3.9/linux/drivers/block/ida_ioctl.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ida_ioctl.h	Mon Jul  5 19:52:13 1999
@@ -0,0 +1,83 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  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.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef IDA_IOCTL_H
+#define IDA_IOCTL_H
+
+#include "ida_cmd.h"
+#include "cpqarray.h"
+
+#define IDAGETDRVINFO		0x27272828
+#define IDAPASSTHRU		0x28282929
+#define IDAGETCTLRSIG		0x29293030
+#define IDAREVALIDATEVOLS	0x30303131
+#define IDADRIVERVERSION	0x31313232
+
+/*
+ * Normally, the ioctl determines the logical unit for this command by
+ * the major,minor number of the fd passed to ioctl.  If you need to send
+ * a command to a different/nonexistant unit (such as during config), you
+ * can override the normal behavior by setting the unit valid bit. (Normally,
+ * it should be zero) The controller the command is sent to is still
+ * determined by the major number of the open device.
+ */
+
+#define UNITVALID	0x80
+typedef struct {
+	__u8	cmd;
+	__u8	rcode;
+	__u8	unit;
+	__u32	blk;
+	__u16	blk_cnt;
+
+/* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */
+	struct {
+		void	*addr;
+		size_t	size;
+	} sg[SG_MAX];
+	int	sg_cnt;
+
+	union ctlr_cmds {
+		drv_info_t		drv;
+		unsigned char		buf[512];
+
+		id_ctlr_t		id_ctlr;
+		drv_param_t		drv_param;
+		id_log_drv_t		id_log_drv;
+		id_log_drv_ext_t	id_log_drv_ext;
+		sense_log_drv_stat_t	sense_log_drv_stat;
+		id_phys_drv_t		id_phys_drv;
+		blink_drv_leds_t	blink_drv_leds;
+		sense_blink_leds_t	sense_blink_leds;
+		config_t		config;
+		reorder_log_drv_t	reorder_log_drv;
+		label_log_drv_t		label_log_drv;
+		surf_delay_t		surf_delay;
+		overhead_delay_t	overhead_delay;
+		mp_delay_t		mp_delay;
+		scsi_param_t		scsi_param;
+	} c;
+} ida_ioctl_t;
+
+#endif /* IDA_IOCTL_H */
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.3.9/linux/drivers/block/ide-disk.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide-disk.c	Mon Jul  5 20:13:59 1999
@@ -776,8 +776,9 @@
 			drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
 	if (drive->using_dma) {
-		if  ((id->field_valid & 4) && (id->word93 & 0x2000) &&
-		     (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
+		if ((id->field_valid & 4) && (id->word93 & 0x2000) &&
+		    (HWIF(drive)->udma_four) &&
+		    (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
 			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
 		} else if ((id->field_valid & 4) &&
 			   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.3.9/linux/drivers/block/ide-dma.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/ide-dma.c	Thu Jul  1 10:25:38 1999
@@ -91,9 +91,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define IDE_DMA_NEW_LISTINGS		0
+#ifdef IDEDMA_NEW_DRIVE_LISTINGS
 
-#if IDE_DMA_NEW_LISTINGS
 struct drive_list_entry {
 	char * id_model;
 	char * id_firmware;
@@ -130,7 +129,8 @@
 			return 1;
 	return 0;
 }
-#else /* !IDE_DMA_NEW_LISTINGS */
+
+#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
@@ -162,7 +162,7 @@
 				"WDC AC31600H",
  				NULL};
 
-#endif /* IDE_DMA_NEW_LISTINGS */
+#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
@@ -314,8 +314,7 @@
 {
 	struct hd_driveid *id = drive->id;
 
-#if IDE_DMA_NEW_LISTINGS
-
+#ifdef IDEDMA_NEW_DRIVE_LISTINGS
 	if (good_bad) {
 		return in_drive_list(id, drive_whitelist);
 	} else {
@@ -324,8 +323,7 @@
 			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
 		return(blacklist);
 	}
-#else /* !IDE_DMA_NEW_LISTINGS */
-
+#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
 	const char **list;
 
 	if (good_bad) {
@@ -346,7 +344,7 @@
 			}
 		}
 	}
-#endif /* IDE_DMA_NEW_LISTINGS */
+#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
 	return 0;
 }
 
@@ -359,12 +357,12 @@
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive))
 			return hwif->dmaproc(ide_dma_off, drive);
-#if 0
+#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->dma_ultra & (id->dma_ultra >> 11) & 3))
 				return hwif->dmaproc(ide_dma_on, drive);
-#endif
+#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))
@@ -527,7 +525,7 @@
 		}
 	}
 	if (dma_base) {
-		if (extra) /* PDC20246 & HPT343 */
+		if (extra) /* PDC20246, PDC20262, & HPT343 */
 			request_region(dma_base+16, extra, name);
 		dma_base += hwif->channel ? 8 : 0;
 		hwif->dma_extra = extra;
@@ -538,13 +536,15 @@
 				 * 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:
-				outb(inb(dma_base+2) & 0x60, dma_base+2);
 				/*
 				 * Ali 15x3 chipsets know as ALI IV and V report
 				 * this as simplex, skip this test for them.
 				 */
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+				outb(inb(dma_base+2) & 0x60, dma_base+2);
 				if (inb(dma_base+2) & 0x80) {
 					printk("%s: simplex device: DMA forced\n", name);
 				}
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.9/linux/drivers/block/ide-pci.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide-pci.c	Mon Jul  5 20:13:59 1999
@@ -51,7 +51,7 @@
 #define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
 #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_HPT343	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
 #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})
@@ -156,14 +156,14 @@
 #define PCI_AEC6210	NULL
 #endif
 
-#ifdef CONFIG_BLK_DEV_HPT343
-extern unsigned int pci_init_hpt343(struct pci_dev *, const char *);
-extern void ide_init_hpt343(ide_hwif_t *);
-#define PCI_HPT343	&pci_init_hpt343
-#define	INIT_HPT343	&ide_init_hpt343
+#ifdef CONFIG_BLK_DEV_HPT34X
+extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
+extern void ide_init_hpt34x(ide_hwif_t *);
+#define PCI_HPT34X	&pci_init_hpt34x
+#define	INIT_HPT34X	&ide_init_hpt34x
 #else
-#define PCI_HPT343	NULL
-#define	INIT_HPT343	NULL
+#define PCI_HPT34X	NULL
+#define	INIT_HPT34X	NULL
 #endif
 
 #define INIT_SAMURAI	NULL
@@ -212,7 +212,7 @@
 	{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_HPT343,	"HPT343",	PCI_HPT343,	INIT_HPT343,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
+	{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 },
@@ -231,19 +231,22 @@
 			{
 				int i;
 				unsigned short pcicmd = 0;
-				unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+				unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
 
 				pci_write_config_byte(dev, 0x80, 0x00);
-				dev->base_address[0] = (hpt343IoBase + 0x20);
-				dev->base_address[1] = (hpt343IoBase + 0x34);
-				dev->base_address[2] = (hpt343IoBase + 0x28);
-				dev->base_address[3] = (hpt343IoBase + 0x3c);
+				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))
+				if (!(pcicmd & PCI_COMMAND_MEMORY)) {
 					pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+				} else {
+					pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+				}
 			}
 		case PCI_DEVICE_ID_PROMISE_20246:
 		case PCI_DEVICE_ID_PROMISE_20262:
@@ -422,7 +425,7 @@
 		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
 #endif
 	}
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343)) {
+	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
 		/*
 		 * Since there are two cards that report almost identically,
 		 * the only discernable difference is the values
@@ -483,16 +486,19 @@
 		}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513))
+		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) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-#ifdef CONFIG_BLK_DEV_HPT343
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) ||
-#endif
+#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_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);
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.9/linux/drivers/block/ide-probe.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide-probe.c	Mon Jul  5 20:13:59 1999
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-probe.c	Version 1.04  March 10, 1999
+ *  linux/drivers/block/ide-probe.c	Version 1.05  July 3, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -18,8 +18,11 @@
  *			 by Andrea Arcangeli
  * Version 1.03		fix for (hwif->chipset == ide_4drives)
  * Version 1.04		fixed buggy treatments of known flash memory cards
- *			fix for (hwif->chipset == ide_pdc4030)
+ *
+ * Version 1.05		fix for (hwif->chipset == ide_pdc4030)
  *			added ide6/7
+ *			allowed for secondary flash card to be detectable
+ *			 with new flag : drive->ata_flash : 1;
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -141,8 +144,10 @@
 	 */
 	if (drive_is_flashcard(drive)) {
 		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
-		mate->present = 0;
-		mate->noprobe = 1;
+		if (!mate->ata_flash) {
+			mate->present = 0;
+			mate->noprobe = 1;
+		}
 	}
 	drive->media = ide_disk;
 	printk("ATA DISK drive\n");
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.3.9/linux/drivers/block/ide-tape.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide-tape.c	Tue Jul  6 19:16:55 1999
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/block/ide-tape.c	Version 1.14		Dec  30, 1998
+ * linux/drivers/block/ide-tape.c	Version 1.15		Jul   4, 1999
  *
- * Copyright (C) 1995 - 1998 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
  * This driver was constructed as a student project in the software laboratory
  * of the faculty of electrical engineering in the Technion - Israel's
@@ -214,6 +214,9 @@
  * Ver 1.13  Jan  2 98   Add "speed == 0" work-around for HP COLORADO 5GB
  * Ver 1.14  Dec 30 98   Partial fixes for the Sony/AIWA tape drives.
  *                       Replace cli()/sti() with hwgroup spinlocks.
+ * Ver 1.15  Mar 25 99   Fix SMP race condition by replacing hwgroup
+ *                        spinlock with private per-tape spinlock.
+ *                       Fix use of freed memory.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -697,6 +700,7 @@
 	int excess_bh_size;			/* Wasted space in each stage */
 
 	unsigned int flags;			/* Status/Action flags */
+	spinlock_t spinlock;			/* protects the ide-tape queue */
 } idetape_tape_t;
 
 /*
@@ -1443,7 +1447,7 @@
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "Reached idetape_add_stage_tail\n");
 #endif /* IDETAPE_DEBUG_LOG */
-	spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+	spin_lock_irqsave(&tape->spinlock, flags);
 	stage->next=NULL;
 	if (tape->last_stage != NULL)
 		tape->last_stage->next=stage;
@@ -1454,7 +1458,7 @@
 		tape->next_stage=tape->last_stage;
 	tape->nr_stages++;
 	tape->nr_pending_stages++;
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&tape->spinlock, flags);
 }
 
 /*
@@ -1556,7 +1560,9 @@
 	ide_drive_t *drive = hwgroup->drive;
 	struct request *rq = hwgroup->rq;
 	idetape_tape_t *tape = drive->driver_data;
+	unsigned long flags;
 	int error;
+	int remove_stage = 0;
 
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "Reached idetape_end_request\n");
@@ -1571,6 +1577,7 @@
 	if (error)
 		tape->failed_pc = NULL;
 
+	spin_lock_irqsave(&tape->spinlock, flags);
 	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
@@ -1581,7 +1588,7 @@
 				if (error == IDETAPE_ERROR_EOD)
 					idetape_abort_pipeline (drive);
 			}
-			idetape_remove_stage_head (drive);
+			remove_stage = 1;
 		}
 		if (tape->next_stage != NULL) {
 			idetape_active_next_stage (drive);
@@ -1599,6 +1606,9 @@
 			idetape_increase_max_pipeline_stages (drive);
 	}
 	ide_end_drive_cmd (drive, 0, 0);
+	if (remove_stage)
+		idetape_remove_stage_head (drive);
+	spin_unlock_irqrestore(&tape->spinlock, flags);
 }
 
 /*
@@ -2340,6 +2350,7 @@
 static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
 {
 	DECLARE_MUTEX_LOCKED(sem);
+	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
 	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
@@ -2348,9 +2359,9 @@
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	rq->sem = &sem;
-	spin_unlock(&HWGROUP(drive)->spinlock);
+	spin_unlock(&tape->spinlock);
 	down(&sem);
-	spin_lock_irq(&HWGROUP(drive)->spinlock);
+	spin_lock_irq(&tape->spinlock);
 }
 
 /*
@@ -2424,10 +2435,10 @@
 		 */
 		return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh));
 	}
-	spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+	spin_lock_irqsave(&tape->spinlock, flags);
 	if (tape->active_stage == tape->first_stage)
 		idetape_wait_for_request(drive, tape->active_data_request);
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&tape->spinlock, flags);
 
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -2476,12 +2487,12 @@
 	 *	Pay special attention to possible race conditions.
 	 */
 	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
-		spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+		spin_lock_irqsave(&tape->spinlock, flags);
 		if (idetape_pipeline_active (tape)) {
 			idetape_wait_for_request(drive, tape->active_data_request);
-			spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+			spin_unlock_irqrestore(&tape->spinlock, flags);
 		} else {
-			spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+			spin_unlock_irqrestore(&tape->spinlock, flags);
 			idetape_insert_pipeline_into_queue (drive);
 			if (idetape_pipeline_active (tape))
 				continue;
@@ -2538,11 +2549,11 @@
 	if (tape->first_stage == NULL)
 		return;
 
-	spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+	spin_lock_irqsave(&tape->spinlock, flags);
 	tape->next_stage = NULL;
 	if (idetape_pipeline_active (tape))
 		idetape_wait_for_request(drive, tape->active_data_request);
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&tape->spinlock, flags);
 
 	while (tape->first_stage != NULL)
 		idetape_remove_stage_head (drive);
@@ -2562,7 +2573,7 @@
 	if (!idetape_pipeline_active (tape))
 		idetape_insert_pipeline_into_queue (drive);
 
-	spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+	spin_lock_irqsave(&tape->spinlock, flags);
 	if (!idetape_pipeline_active (tape))
 		goto abort;
 #if IDETAPE_DEBUG_BUGS
@@ -2572,7 +2583,7 @@
 #endif /* IDETAPE_DEBUG_BUGS */
 	idetape_wait_for_request(drive, &tape->last_stage->rq);
 abort:
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&tape->spinlock, flags);
 }
 
 static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
@@ -2817,10 +2828,10 @@
 			 *	Wait until the first read-ahead request
 			 *	is serviced.
 			 */
-			spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+			spin_lock_irqsave(&tape->spinlock, flags);
 			if (tape->active_stage == tape->first_stage)
 				idetape_wait_for_request(drive, tape->active_data_request);
-			spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+			spin_unlock_irqrestore(&tape->spinlock, flags);
 
 			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
 				count++;
@@ -3564,6 +3575,8 @@
 	u16 speed;
 	struct idetape_id_gcw gcw;
 
+	memset (tape, 0, sizeof (idetape_tape_t));
+	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
 	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
 #ifdef CONFIG_BLK_DEV_IDEPCI
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.9/linux/drivers/block/ide.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide.c	Mon Jul  5 20:13:59 1999
@@ -297,7 +297,8 @@
 		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
 		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
 		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
-		 || !strncmp(id->model, "HAGIWARA HPC", 12))	/* Hagiwara */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
+		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
 		{
 			return 1;	/* yes, it is a flash memory card */
 		}
@@ -1353,7 +1354,7 @@
 			(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
 			printk("%s: timeout waiting for DMA\n", drive->name);
 	/*
-	 *  need something here for HX PIIX3 UDMA and HPT343.......AMH
+	 *  need something here for HPT34X.......AMH
 	 *  irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }
 	 */
 		}
@@ -1898,6 +1899,7 @@
 	hwif->irq = old_hwif.irq;
 	hwif->major = old_hwif.major;
 	hwif->proc = old_hwif.proc;
+	hwif->udma_four = old_hwif.udma_four;
 	hwif->chipset = old_hwif.chipset;
 	hwif->pci_dev = old_hwif.pci_dev;
 	hwif->pci_devid = old_hwif.pci_devid;
@@ -2235,6 +2237,27 @@
 	while (0 < (signed long)(timeout - jiffies));
 }
 
+int ide_config_drive_speed (ide_drive_t *drive, byte speed)
+{
+	int err;
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+	SELECT_DRIVE(HWIF(drive), drive);
+	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+	OUT_BYTE(speed, IDE_NSECTOR_REG);
+	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+
+	err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+
+	return(err);
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2317,10 +2340,15 @@
 			}
 			if ((((byte *)arg)[0] == WIN_SETFEATURES) &&
 			    (((byte *)arg)[1] > 66) &&
-			    (((byte *)arg)[2] == 3) &&
-			    ((drive->id->word93 & 0x2000) == 0)) {
-				printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
-				goto abort;
+			    (((byte *)arg)[2] == 3)) {
+				if (!HWIF(drive)->udma_four) {
+					printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name);
+					goto abort;
+				}
+				if ((drive->id->word93 & 0x2000) == 0) {
+					printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
+					goto abort;
+				}
 			}
 			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
 			if (!err &&
@@ -2581,6 +2609,9 @@
  *
  * "hdx=swapdata"	: when the drive is a disk, byte swap all data
  * "hdx=bswap"		: same as above..........
+ * "hdx=flash"		: allows for more than one ata_flash disk to be
+ *				registered. In most cases, only one device
+ *				will be present.
  *
  * "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in MHz,
  *				where "xx" is between 20 and 66 inclusive,
@@ -2667,7 +2698,7 @@
 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
 		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
 				"serialize", "autotune", "noautotune",
-				"slow", "swapdata", "bswap", NULL};
+				"slow", "swapdata", "bswap", "flash", NULL};
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
 		unit = unit % MAX_DRIVES;
@@ -2708,6 +2739,9 @@
 			case -10:
 				drive->bswap = 1;
 				goto done;
+			case -11:
+				drive->ata_flash = 1;
+				goto done;
 			case 3: /* cyl,head,sect */
 				drive->media	= ide_disk;
 				drive->cyl	= drive->bios_cyl  = vals[0];
@@ -3416,6 +3450,7 @@
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_wait_cmd);
 EXPORT_SYMBOL(ide_delay_50ms);
+EXPORT_SYMBOL(ide_config_drive_speed);
 EXPORT_SYMBOL(ide_stall_queue);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(ide_add_proc_entries);
diff -u --recursive --new-file v2.3.9/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.9/linux/drivers/block/ll_rw_blk.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ll_rw_blk.c	Mon Jul  5 19:52:52 1999
@@ -347,6 +347,9 @@
 /* for SCSI devices, call request_fn unconditionally */
 	if (scsi_blk_major(MAJOR(req->rq_dev)))
 		queue_new_request = 1;
+	if (MAJOR(req->rq_dev) >= COMPAQ_SMART2_MAJOR+0 &&
+	    MAJOR(req->rq_dev) <= COMPAQ_SMART2_MAJOR+7)
+		queue_new_request = 1;
 out:
 	if (queue_new_request)
 		(dev->request_fn)();
@@ -506,6 +509,14 @@
 	     case SCSI_DISK7_MAJOR:
 	     case SCSI_CDROM_MAJOR:
 	     case I2O_MAJOR:
+	     case COMPAQ_SMART2_MAJOR+0:
+	     case COMPAQ_SMART2_MAJOR+1:
+	     case COMPAQ_SMART2_MAJOR+2:
+	     case COMPAQ_SMART2_MAJOR+3:
+	     case COMPAQ_SMART2_MAJOR+4:
+	     case COMPAQ_SMART2_MAJOR+5:
+	     case COMPAQ_SMART2_MAJOR+6:
+	     case COMPAQ_SMART2_MAJOR+7:
 
 		do {
 			if (req->sem)
@@ -717,7 +728,7 @@
 	wake_up(&wait_for_request);
 }
 
-__initfunc(int blk_dev_init(void))
+int __init blk_dev_init(void)
 {
 	struct request * req;
 	struct blk_dev_struct *dev;
diff -u --recursive --new-file v2.3.9/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.9/linux/drivers/block/loop.c	Sun May 30 10:17:43 1999
+++ linux/drivers/block/loop.c	Mon Jul  5 20:15:24 1999
@@ -27,7 +27,13 @@
  * - Should use an own CAP_* category instead of CAP_SYS_ADMIN 
  * - Should use the underlying filesystems/devices read function if possible
  *   to support read ahead (and for write)
- */
+ *
+ * WARNING/FIXME:
+ * - The block number as IV passing to low level transfer functions is broken:
+ *   it passes the underlying device's block number instead of the
+ *   offset. This makes it change for a given block when the file is 
+ *   moved/restored/copied and also doesn't work over NFS. 
+ */ 
 
 #include <linux/module.h>
 
@@ -107,7 +113,7 @@
 
 static int xor_status(struct loop_device *lo, struct loop_info *info)
 {
-	if (info->lo_encrypt_key_size < 0)
+	if (info->lo_encrypt_key_size <= 0)
 		return -EINVAL;
 	return 0;
 }
@@ -369,6 +375,10 @@
 		   a file structure */
 		lo->lo_backing_file = NULL;
 	} else if (S_ISREG(inode->i_mode)) {
+		if (!inode->i_op->bmap) { 
+			printk(KERN_ERR "loop: device has no block access/not implemented\n");
+			goto out_putf;
+		}
 
 		/* Backed by a regular file - we need to hold onto
 		   a file structure for this file.  We'll use it to
@@ -391,6 +401,7 @@
 			lo->lo_backing_file->f_dentry = file->f_dentry;
 			lo->lo_backing_file->f_op = file->f_op;
 			lo->lo_backing_file->private_data = file->private_data;
+			file_moveto(lo->lo_backing_file, file);
 
 			error = get_write_access(inode);
 			if (error) {
@@ -504,8 +515,6 @@
 	if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
 		return -EINVAL;
 	type = info.lo_encrypt_type; 
-	if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR)
-		return -EINVAL;
 	if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
 		return -EINVAL;
 	err = loop_release_xfer(lo);
diff -u --recursive --new-file v2.3.9/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.3.9/linux/drivers/block/nbd.c	Wed May 12 08:41:12 1999
+++ linux/drivers/block/nbd.c	Mon Jul  5 20:07:02 1999
@@ -401,7 +401,7 @@
 		return 0;
 	case NBD_SET_SIZE_BLOCKS:
 		nbd_sizes[dev] = arg;
-		nbd_bytesizes[dev] = arg << nbd_blksize_bits[dev];
+		nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev];
 		return 0;
 	case NBD_DO_IT:
 		if (!lo->file)
diff -u --recursive --new-file v2.3.9/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c
--- v2.3.9/linux/drivers/block/pdc202xx.c	Wed May 26 16:55:40 1999
+++ linux/drivers/block/pdc202xx.c	Thu Jul  1 10:25:38 1999
@@ -90,8 +90,6 @@
 
 #define PDC202XX_DEBUG_DRIVE_INFO		0
 #define PDC202XX_DECODE_REGISTER_INFO		0
-#define PDC202XX_FORCE_BURST_BIT		0
-#define PDC202XX_FORCE_MASTER_MODE		0
 
 extern char *ide_xfer_verbose (byte xfer_rate);
 
@@ -225,16 +223,12 @@
 	switch(drive_number) {
 		case 0:	drive_pci = 0x60;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
 			pci_read_config_byte(dev, (drive_pci), &test1);
 			if (!(test1 & SYNC_ERRDY_EN))
 				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
 			break;
 		case 1:	drive_pci = 0x64;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
 			pci_read_config_byte(dev, 0x60, &test1);
 			pci_read_config_byte(dev, (drive_pci), &test2);
 			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -242,16 +236,12 @@
 			break;
 		case 2:	drive_pci = 0x68;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
 			pci_read_config_byte(dev, (drive_pci), &test1);
 			if (!(test1 & SYNC_ERRDY_EN))
 				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
 			break;
 		case 3:	drive_pci = 0x6c;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
 			pci_read_config_byte(dev, 0x68, &test1);
 			pci_read_config_byte(dev, (drive_pci), &test2);
 			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -415,7 +405,7 @@
 		return ide_dma_off_quietly;
 	}
 
-	err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+	err = ide_config_drive_speed(drive, speed);
 
 #if PDC202XX_DECODE_REGISTER_INFO
 	pci_read_config_byte(dev, (drive_pci), &AP);
@@ -436,8 +426,6 @@
 	printk("0x%08x\n", drive_conf);
 #endif /* PDC202XX_DEBUG_DRIVE_INFO */
 
-chipset_is_set:
-
 	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 : 
@@ -533,7 +521,7 @@
 		(primary_mode & 1) ? "MASTER" : "PCI",
 		(secondary_mode & 1) ? "MASTER" : "PCI" );
 
-#if PDC202XX_FORCE_BURST_BIT
+#ifdef PDC202XX_FORCE_BURST_BIT
 	if (!(udma_speed_flag & 1)) {
 		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
 		outb(udma_speed_flag|1, high_16 + 0x001f);
@@ -541,7 +529,7 @@
 	}
 #endif /* PDC202XX_FORCE_BURST_BIT */
 
-#if PDC202XX_FORCE_MASTER_MODE
+#ifdef PDC202XX_FORCE_MASTER_MODE
 	if (!(primary_mode & 1)) {
 		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
 			name, primary_mode, (primary_mode|1));
diff -u --recursive --new-file v2.3.9/linux/drivers/block/piix.c linux/drivers/block/piix.c
--- v2.3.9/linux/drivers/block/piix.c	Wed Jun  2 22:21:51 1999
+++ linux/drivers/block/piix.c	Sat Jul  3 10:45:04 1999
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/piix.c	Version 0.23	May 29, 1999
+ * linux/drivers/block/piix.c	Version 0.24	June 28, 1999
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
@@ -44,8 +44,15 @@
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
  *
+ * #if 0
+ * int err;
+ * err = ide_config_drive_speed(drive, speed);
+ * (void) ide_config_drive_speed(drive, speed);
+ * #else
+ * #endif
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
@@ -62,6 +69,7 @@
 
 extern char *ide_xfer_verbose (byte xfer_rate);
 
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
 /*
  *
  */
@@ -91,6 +99,7 @@
 			return 0;
 	}
 }
+#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
 
 /*
  *  Based on settings done by AMI BIOS
@@ -111,11 +120,7 @@
 				    { 2, 1 },
 				    { 2, 3 }, };
 
-#if 1
 	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-#else
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-#endif
 	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
 	if (is_slave) {
 		master_data = master_data | 0x4000;
@@ -142,6 +147,8 @@
 	restore_flags(flags);
 }
 
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
+
 static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra)
 {
 	struct hd_driveid *id = drive->id;
@@ -246,17 +253,13 @@
 		}
 		speed = XFER_SW_DMA_2;
         } else {
-#if 0
-		speed = XFER_PIO_0;
-#else
 		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-#endif
 	}
 
 	restore_flags(flags);
 	piix_tune_drive(drive, piix_dma_2_pio(speed));
 
-	(void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+	(void) ide_config_drive_speed(drive, speed);
 
 #if PIIX_DEBUG_DRIVE_INFO
 	printk("%s: %s drive%d ",
@@ -284,11 +287,19 @@
 	/* Other cases are done by generic IDE-DMA code. */
 	return ide_dmaproc(func, drive);
 }
+#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
 
 void ide_init_piix (ide_hwif_t *hwif)
 {
 	hwif->tuneproc = &piix_tune_drive;
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
 	if (hwif->dma_base) {
 		hwif->dmaproc = &piix_dmaproc;
+	} else
+#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
+	{
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
 	}
+
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h
--- v2.3.9/linux/drivers/block/smart1,2.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/smart1,2.h	Mon Jul  5 19:52:52 1999
@@ -0,0 +1,274 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    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, GOOD TITLE or
+ *    NON INFRINGEMENT.  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.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+
+/*
+ * This file contains the controller communication implementation for
+ * Compaq SMART-1 and SMART-2 controllers.  To the best of my knowledge,
+ * this should support:
+ *
+ *  PCI:
+ *  SMART-2/P, SMART-2DH, SMART-2SL, SMART-221, SMART-3100ES, SMART-3200
+ *  Integerated SMART Array Controller, SMART-4200, SMART-4250ES
+ *
+ *  EISA:
+ *  SMART-2/E, SMART, IAES, IDA-2, IDA
+ */
+
+/*
+ * Memory mapped FIFO interface (SMART 42xx cards)
+ */
+static void smart4_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+        writel(c->busaddr, h->vaddr + S42XX_REQUEST_PORT_OFFSET);
+}
+
+/*  
+ *  This card is the oposite of the other cards.  
+ *   0 turns interrupts on... 
+ *   0x08 turns them off... 
+ */
+static void smart4_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+	if (val) 
+	{ /* Turn interrupts on */
+		writel(0, h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET);
+	} else /* Turn them off */
+	{
+        	writel( S42XX_INTR_OFF, 
+			h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET);
+	}
+}
+
+/*
+ *  For this card fifo is full if reading this port returns 0! 
+ * 
+ */ 
+static unsigned long smart4_fifo_full(ctlr_info_t *h)
+{
+	
+        return (~readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET));
+}
+
+/* This type of controller returns -1 if the fifo is empty, 
+ *    Not 0 like the others.
+ *    And we need to let it know we read a value out 
+ */ 
+static unsigned long smart4_completed(ctlr_info_t *h)
+{
+	long register_value 
+		= readl(h->vaddr + S42XX_REPLY_PORT_OFFSET);
+
+	/* Fifo is empty */
+	if( register_value == -1)
+		return 0; 	
+
+	/* Need to let it know we got the reply */
+	/* We do this by writing a 0 to the port we just read from */
+	writel(0, h->vaddr + S42XX_REPLY_PORT_OFFSET);
+
+	return ((unsigned long) register_value); 
+}
+
+ /*
+ *  This hardware returns interrupt pending at a different place and 
+ *  it does not tell us if the fifo is empty, we will have check  
+ *  that by getting a 0 back from the comamnd_completed call. 
+ */
+static unsigned long smart4_intr_pending(ctlr_info_t *h)
+{
+	unsigned long register_value  = 
+		readl(h->vaddr + S42XX_INTR_STATUS);
+
+	if( register_value &  S42XX_INTR_PENDING) 
+		return  FIFO_NOT_EMPTY;	
+	return 0 ;
+}
+
+static struct access_method smart4_access = {
+	smart4_submit_command,
+	smart4_intr_mask,
+	smart4_fifo_full,
+	smart4_intr_pending,
+	smart4_completed,
+};
+
+/*
+ * Memory mapped FIFO interface (PCI SMART2 and SMART 3xxx cards)
+ */
+static void smart2_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+	writel(c->busaddr, h->vaddr + COMMAND_FIFO);
+}
+
+static void smart2_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+	writel(val, h->vaddr + INTR_MASK);
+}
+
+static unsigned long smart2_fifo_full(ctlr_info_t *h)
+{
+	return readl(h->vaddr + COMMAND_FIFO);
+}
+
+static unsigned long smart2_completed(ctlr_info_t *h)
+{
+	return readl(h->vaddr + COMMAND_COMPLETE_FIFO);
+}
+
+static unsigned long smart2_intr_pending(ctlr_info_t *h)
+{
+	return readl(h->vaddr + INTR_PENDING);
+}
+
+static struct access_method smart2_access = {
+	smart2_submit_command,
+	smart2_intr_mask,
+	smart2_fifo_full,
+	smart2_intr_pending,
+	smart2_completed,
+};
+
+/*
+ *  IO access for SMART-2/E cards
+ */
+static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+	outl(c->busaddr, h->ioaddr + COMMAND_FIFO);
+}
+
+static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+	outl(val, h->ioaddr + INTR_MASK);
+}
+
+static unsigned long smart2e_fifo_full(ctlr_info_t *h)
+{
+	return inl(h->ioaddr + COMMAND_FIFO);
+}
+
+static unsigned long smart2e_completed(ctlr_info_t *h)
+{
+	return inl(h->ioaddr + COMMAND_COMPLETE_FIFO);
+}
+
+static unsigned long smart2e_intr_pending(ctlr_info_t *h)
+{
+	return inl(h->ioaddr + INTR_PENDING);
+}
+
+static struct access_method smart2e_access = {
+	smart2e_submit_command,
+	smart2e_intr_mask,
+	smart2e_fifo_full,
+	smart2e_intr_pending,
+	smart2e_completed,
+};
+
+/*
+ *  IO access for older SMART-1 type cards
+ */
+#define SMART1_SYSTEM_MASK		0xC8E
+#define SMART1_SYSTEM_DOORBELL		0xC8F
+#define SMART1_LOCAL_MASK		0xC8C
+#define SMART1_LOCAL_DOORBELL		0xC8D
+#define SMART1_INTR_MASK		0xC89
+#define SMART1_LISTADDR			0xC90
+#define SMART1_LISTLEN			0xC94
+#define SMART1_TAG			0xC97
+#define SMART1_COMPLETE_ADDR		0xC98
+#define SMART1_LISTSTATUS		0xC9E
+
+#define CHANNEL_BUSY			0x01
+#define CHANNEL_CLEAR			0x02
+
+static void smart1_submit_command(ctlr_info_t *h, cmdlist_t *c)
+{
+	/*
+	 * This __u16 is actually a bunch of control flags on SMART
+	 * and below.  We want them all to be zero.
+	 */
+	c->hdr.size = 0;
+
+	outb(CHANNEL_CLEAR, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+
+	outl(c->busaddr, h->ioaddr + SMART1_LISTADDR);
+	outw(c->size, h->ioaddr + SMART1_LISTLEN);
+
+	outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL);
+}
+
+static void smart1_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+	if (val == 1) {
+		outb(0xFD, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+		outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL);
+		outb(0x01, h->ioaddr + SMART1_INTR_MASK);
+		outb(0x01, h->ioaddr + SMART1_SYSTEM_MASK);
+	} else {
+		outb(0, h->ioaddr + 0xC8E);
+	}
+}
+
+static unsigned long smart1_fifo_full(ctlr_info_t *h)
+{
+	unsigned char chan;
+	chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR;
+	return chan;
+}
+
+static unsigned long smart1_completed(ctlr_info_t *h)
+{
+	unsigned char status;
+	unsigned long cmd;
+
+	if (inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) {
+		outb(CHANNEL_BUSY, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+
+		cmd = inl(h->ioaddr + SMART1_COMPLETE_ADDR);
+		status = inb(h->ioaddr + SMART1_LISTSTATUS);
+
+		outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL);
+
+		if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status;
+	} else {
+		cmd = 0;
+	}
+	return cmd;
+}
+
+static unsigned long smart1_intr_pending(ctlr_info_t *h)
+{
+	unsigned char chan;
+	chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY;
+	return chan;
+}
+
+static struct access_method smart1_access = {
+	smart1_submit_command,
+	smart1_intr_mask,
+	smart1_fifo_full,
+	smart1_intr_pending,
+	smart1_completed,
+};
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c
--- v2.3.9/linux/drivers/cdrom/aztcd.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/aztcd.c	Tue Jul  6 19:05:48 1999
@@ -1087,7 +1087,7 @@
 #ifdef AZT_KERNEL_PRIOR_2_1
 void aztcd_setup(char *str, int *ints)
 #else
-__initfunc(void aztcd_setup(char *str, int *ints))
+void __init aztcd_setup(char *str, int *ints)
 #endif
 {  if (ints[0] > 0)
       azt_port = ints[1];
@@ -1617,7 +1617,7 @@
 #ifdef AZT_KERNEL_PRIOR_2_1
 int aztcd_init(void)
 #else
-__initfunc(int aztcd_init(void))
+int __init aztcd_init(void)
 #endif
 {       long int count, max_count;
 	unsigned char result[50];
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.3.9/linux/drivers/cdrom/cdu31a.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/cdu31a.c	Tue Jul  6 19:05:48 1999
@@ -3251,10 +3251,10 @@
 /* The different types of disc loading mechanisms supported */
 static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" };
 
-__initfunc(static void
+static void __init 
 get_drive_configuration(unsigned short base_io,
                         unsigned char res_reg[],
-                        unsigned int *res_size))
+                        unsigned int *res_size)
 {
    int retry_count;
 
@@ -3318,9 +3318,9 @@
 /*
  * Set up base I/O and interrupts, called from main.c.
  */
-__initfunc(void
+void __init 
 cdu31a_setup(char *strings,
-	     int  *ints))
+	     int  *ints)
 {
    if (ints[0] > 0)
    {
@@ -3349,8 +3349,8 @@
 /*
  * Initialize the driver.
  */
-__initfunc(int
-cdu31a_init(void))
+int __init 
+cdu31a_init(void)
 {
    struct s_sony_drive_config drive_config;
    unsigned int res_size;
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- v2.3.9/linux/drivers/cdrom/cm206.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/cm206.c	Tue Jul  6 19:05:48 1999
@@ -1294,7 +1294,7 @@
    check_region, 15 bits of one port and 6 of another make things
    likely enough to accept the region on the first hit...
  */
-__initfunc(int probe_base_port(int base))
+int __init probe_base_port(int base)
 {
   int b=0x300, e=0x370;		/* this is the range of start addresses */
   volatile int fool, i;
@@ -1314,7 +1314,7 @@
 
 #if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
 /* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-__initfunc(int probe_irq(int nr)) {
+int __init probe_irq(int nr){
   int irqs, irq;
   outw(dc_normal | READ_AHEAD, r_data_control);	/* disable irq-generation */
   sti(); 
@@ -1328,7 +1328,7 @@
 }
 #endif
 
-__initfunc(int cm206_init(void))
+int __init cm206_init(void)
 {
   uch e=0;
   long int size=sizeof(struct cm206_struct);
@@ -1413,7 +1413,7 @@
 
 static int cm206[2] = {0,0};	/* for compatible `insmod' parameter passing */
 
-__initfunc(void parse_options(void))
+void __init parse_options(void)
 {
   int i;
   for (i=0; i<2; i++) {
@@ -1447,7 +1447,7 @@
 
 /* This setup function accepts either `auto' or numbers in the range
  * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */
-__initfunc(void cm206_setup(char *s, int *p))
+void __init cm206_setup(char *s, int *p)
 {
   int i;
   if (!strcmp(s, "auto")) auto_probe=1;
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
--- v2.3.9/linux/drivers/cdrom/gscd.c	Sat May 15 15:05:36 1999
+++ linux/drivers/cdrom/gscd.c	Tue Jul  6 19:05:48 1999
@@ -194,7 +194,7 @@
 }
 
 
-__initfunc(void gscd_setup (char *str, int *ints))
+void __init gscd_setup (char *str, int *ints)
 {
   if (ints[0] > 0) 
   {
@@ -851,7 +851,7 @@
      return;
 }
 
-__initfunc(int find_drives (void))
+int __init find_drives (void)
 {
 int *pdrv;
 int drvnum;
@@ -902,7 +902,7 @@
     return drvnum;
 }    
 
-__initfunc(void init_cd_drive ( int num ))
+void __init init_cd_drive ( int num )
 {
 char resp [50];
 int  i;
@@ -994,7 +994,7 @@
 
 
 /* Test for presence of drive and initialize it.  Called only at boot time. */
-__initfunc(int gscd_init (void))
+int __init gscd_init (void)
 {
    return my_gscd_init ();
 }
@@ -1002,7 +1002,7 @@
 
 /* This is the common initialisation for the GoldStar drive. */
 /* It is called at boot time AND for module init.           */
-__initfunc(int my_gscd_init (void))
+int __init my_gscd_init (void)
 {
 int i;
 int result;
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c
--- v2.3.9/linux/drivers/cdrom/isp16.c	Tue Dec  2 11:41:44 1997
+++ linux/drivers/cdrom/isp16.c	Tue Jul  6 19:05:48 1999
@@ -77,8 +77,8 @@
 #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
 
 
-__initfunc(void
-isp16_setup(char *str, int *ints))
+void __init 
+isp16_setup(char *str, int *ints)
 {
   if ( ints[0] > 0 )
     isp16_cdrom_base = ints[1];
@@ -94,8 +94,8 @@
  *  ISP16 initialisation.
  *
  */
-__initfunc(int
-isp16_init(void))
+int __init 
+isp16_init(void)
 {
   u_char expected_drive;
 
@@ -144,8 +144,8 @@
   return(0);
 }
 
-__initfunc(static short
-isp16_detect(void))
+static short __init 
+isp16_detect(void)
 {
 
   if ( isp16_c929__detect() >= 0 )
@@ -154,8 +154,8 @@
     return(isp16_c928__detect());
 }
 
-__initfunc(static short
-isp16_c928__detect(void))
+static short __init 
+isp16_c928__detect(void)
 {
   u_char ctrl;
   u_char enable_cdrom;
@@ -203,8 +203,8 @@
   return(i);
 }
 
-__initfunc(static short
-isp16_c929__detect(void))
+static short __init 
+isp16_c929__detect(void)
 {
   u_char ctrl;
   u_char tmp;
@@ -230,8 +230,8 @@
   return(2);
 }
 
-__initfunc(static short
-isp16_cdi_config(int base, u_char drive_type, int irq, int dma))
+static short __init 
+isp16_cdi_config(int base, u_char drive_type, int irq, int dma)
 {
   u_char base_code;
   u_char irq_code;
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.3.9/linux/drivers/cdrom/mcd.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/mcd.c	Tue Jul  6 19:05:48 1999
@@ -230,8 +230,7 @@
 };
 
 
-
-__initfunc(void mcd_setup(char *str, int *ints))
+void __init mcd_setup(char *str, int *ints)
 {
    if (ints[0] > 0)
       mcd_port = ints[1];
@@ -1155,7 +1154,7 @@
  * Test for presence of drive and initialize it.  Called at boot time.
  */
 
-__initfunc(int mcd_init(void))
+int __init mcd_init(void)
 {
 	int count;
 	unsigned char result[3];
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v2.3.9/linux/drivers/cdrom/mcdx.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/mcdx.c	Tue Jul  6 19:05:48 1999
@@ -770,7 +770,7 @@
 	return 1;
 }
 
-__initfunc(void mcdx_setup(char *str, int *pi))
+void __init mcdx_setup(char *str, int *pi)
 {
 	if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
 	if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
@@ -1013,7 +1013,7 @@
 
 /* Support functions ************************************************/
 
-__initfunc(int mcdx_init_drive(int drive))
+int __init mcdx_init_drive(int drive)
 {
 	struct s_version version;
 	struct s_drive_stuff* stuffp;
@@ -1174,7 +1174,7 @@
 	return 0;
 }
 
-__initfunc(int mcdx_init(void))
+int __init mcdx_init(void)
 {
 	int drive;
 #ifdef MODULE
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c
--- v2.3.9/linux/drivers/cdrom/optcd.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/optcd.c	Tue Jul  6 19:05:48 1999
@@ -1966,7 +1966,7 @@
 
 /* Returns 1 if a drive is detected with a version string
    starting with "DOLPHIN". Otherwise 0. */
-__initfunc(static int version_ok(void))
+static int __init version_ok(void)
 {
 	char devname[100];
 	int count, i, ch, status;
@@ -2022,7 +2022,7 @@
 
 
 /* Get kernel parameter when used as a kernel driver */
-__initfunc(void optcd_setup(char *str, int *ints))
+void __init optcd_setup(char *str, int *ints)
 {
 	if (ints[0] > 0)
 		optcd_port = ints[1];
@@ -2030,7 +2030,7 @@
 
 /* Test for presence of drive and initialize it. Called at boot time
    or during module initialisation. */
-__initfunc(int optcd_init(void))
+int __init optcd_init(void)
 {
 	int status;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.3.9/linux/drivers/cdrom/sbpcd.c	Sat May 15 15:05:36 1999
+++ linux/drivers/cdrom/sbpcd.c	Tue Jul  6 19:05:48 1999
@@ -3215,7 +3215,7 @@
 }
 #endif FUTURE
 /*==========================================================================*/
-__initfunc(static void check_datarate(void))
+static void __init check_datarate(void)
 {
 	int i=0;
 	
@@ -3285,7 +3285,7 @@
 }
 #endif
 /*==========================================================================*/
-__initfunc(static void ask_mail(void))
+static void __init ask_mail(void)
 {
 	int i;
 	
@@ -3304,7 +3304,7 @@
 	msg(DBG_INF,"infobuf =%s\n", msgbuf);
 }
 /*==========================================================================*/
-__initfunc(static int check_version(void))
+static int __init check_version(void)
 {
 	int i, j, l;
 	int teac_possible=0;
@@ -3602,7 +3602,7 @@
 /*
  * probe for the presence of an interface card
  */
-__initfunc(static int check_card(int port))
+static int __init check_card(int port)
 {
 #undef N_RESPO
 #define N_RESPO 20
@@ -3706,7 +3706,7 @@
 /*
  * probe for the presence of drives on the selected controller
  */
-__initfunc(static int check_drives(void))
+static int __init check_drives(void)
 {
 	int i, j;
 	
@@ -5458,9 +5458,9 @@
  *
  */
 #if (SBPCD_ISSUE-1)
-__initfunc(static void sbpcd_setup(const char *s, int *p))
+static void __init sbpcd_setup(const char *s, int *p)
 #else
-__initfunc(void sbpcd_setup(const char *s, int *p))
+void __init sbpcd_setup(const char *s, int *p)
 #endif
 {
 	setup_done++;
@@ -5512,7 +5512,7 @@
  *        port 0x330, we have to use an offset of 8; so, the real CDROM port
  *        address is 0x338.
  */
-__initfunc(static int config_spea(void))
+static int __init config_spea(void)
 {
 	/*
          * base address offset between configuration port and CDROM port,
@@ -5571,7 +5571,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-__initfunc(int SBPCD_INIT(void))
+int __init SBPCD_INIT(void)
 #endif MODULE
 {
 	int i=0, j=0;
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c
--- v2.3.9/linux/drivers/cdrom/sjcd.c	Wed May 12 13:27:37 1999
+++ linux/drivers/cdrom/sjcd.c	Tue Jul  6 19:05:48 1999
@@ -163,7 +163,7 @@
  * Set up device, i.e., use command line data to set
  * base address.
  */
-__initfunc(void sjcd_setup( char *str, int *ints ))
+void __init sjcd_setup( char *str, int *ints )
 {
    if (ints[0] > 0)
       sjcd_base = ints[1];
@@ -1457,7 +1457,7 @@
  * Test for presence of drive and initialize it. Called at boot time.
  * Probe cdrom, find out version and status.
  */
-__initfunc(int sjcd_init( void )){
+int __init sjcd_init( void ){
   int i;
 
   printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c
--- v2.3.9/linux/drivers/cdrom/sonycd535.c	Wed May 26 09:31:44 1999
+++ linux/drivers/cdrom/sonycd535.c	Tue Jul  6 19:05:48 1999
@@ -1486,8 +1486,8 @@
 /*
  * Initialize the driver.
  */
-__initfunc(int
-sony535_init(void))
+int __init 
+sony535_init(void)
 {
 	struct s535_sony_drive_config drive_config;
 	Byte cmd_buff[3];
@@ -1655,8 +1655,8 @@
  *
  * the address value has to be the existing CDROM port address.
  */
-__initfunc(void
-sonycd535_setup(char *strings, int *ints))
+void __init 
+sonycd535_setup(char *strings, int *ints)
 {
 	/* if IRQ change and default io base desired,
 	 * then call with io base of 0
diff -u --recursive --new-file v2.3.9/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.9/linux/drivers/char/Config.in	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/Config.in	Tue Jul  6 19:16:55 1999
@@ -28,6 +28,9 @@
       tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
    fi
    tristate 'Cyclades async mux support' CONFIG_CYCLADES
+   if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then
+      bool '  Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
+   fi
    bool 'Stallion multiport serial support' CONFIG_STALDRV
    if [ "$CONFIG_STALDRV" = "y" ]; then
      tristate '  Stallion EasyIO or EC8/32 support' CONFIG_STALLION
@@ -52,8 +55,9 @@
 if [ "$CONFIG_PARPORT" != "n" ]; then
   dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   if [ "$CONFIG_PRINTER" != "n" ]; then
-    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+    bool '  Support for console on line printer' CONFIG_LP_CONSOLE
   fi
+  dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
 
 bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
@@ -79,6 +83,9 @@
     comment '   from the tpqic02-support package.  It is available at'
     comment '   metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
   fi
+  dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV
+  dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
+  dep_tristate '  Include support for LML33' CONFIG_VIDEO_LML33 $CONFIG_VIDEO_ZORAN
 fi
 
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
@@ -111,6 +118,7 @@
 
 tristate 'Video For Linux' CONFIG_VIDEO_DEV
 if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
+  dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
   dep_tristate 'AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
     hex '  RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
@@ -123,11 +131,14 @@
   if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
     hex '  Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
   fi
-  dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
-  dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
   dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
     hex '  GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+  fi
+  dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
+  dep_tristate 'TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
+  if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
+    hex '  Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
   fi
   if [ "$CONFIG_PCI" != "n" ]; then
     dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
diff -u --recursive --new-file v2.3.9/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.9/linux/drivers/char/Makefile	Sat May 22 15:02:48 1999
+++ linux/drivers/char/Makefile	Tue Jul  6 19:16:55 1999
@@ -356,6 +356,30 @@
   endif
 endif
 
+ifeq ($(CONFIG_VIDEO_ZORAN),y)
+L_OBJS += buz.o
+else
+  ifeq ($(CONFIG_VIDEO_LML33),m)
+    M_OBJS += buz.o
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_LML33),y)
+L_OBJS += bt856.o bt819.o
+else
+  ifeq ($(CONFIG_VIDEO_LML33),m)
+    M_OBJS += bt856.o bt819.o
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_BUZ),y)
+L_OBJS += saa7111.o saa7185.o
+else
+  ifeq ($(CONFIG_VIDEO_BUZ),m)
+    M_OBJS += saa7111.o saa7185.o
+  endif
+endif
+
 ifeq ($(CONFIG_VIDEO_PMS),y)
 L_OBJS += pms.o
 else
@@ -372,6 +396,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_VIDEO_VINO),y)
+L_OBJS += vino.o
+else
+  ifeq ($(CONFIG_VIDEO_VINO),m)
+  M_OBJS += vino.o
+  endif
+endif
+
 ifeq ($(CONFIG_RADIO_AZTECH),y)
 L_OBJS += radio-aztech.o
 else
@@ -444,6 +476,14 @@
   endif
 endif                                             
 
+ifeq ($(CONFIG_RADIO_TERRATEC),y)
+L_OBJS += radio-terratec.o
+else
+  ifeq ($(CONFIG_RADIO_TERRATEC),m)
+  M_OBJS += radio-terratec.o
+  endif
+endif
+
 ifeq ($(CONFIG_QIC02_TAPE),y)
 L_OBJS += tpqic02.o
 else
@@ -466,6 +506,14 @@
 
 ifdef CONFIG_H8
 LX_OBJS += h8.o
+endif
+
+ifeq ($(CONFIG_PPDEV),y)
+L_OBJS += ppdev.o
+else
+  ifeq ($(CONFIG_PPDEV),m)
+  M_OBJS += ppdev.o
+  endif
 endif
 
 ifeq ($(L_I2C),y)
diff -u --recursive --new-file v2.3.9/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c
--- v2.3.9/linux/drivers/char/acquirewdt.c	Wed Jun  2 11:29:13 1999
+++ linux/drivers/char/acquirewdt.c	Tue Jul  6 19:16:55 1999
@@ -212,7 +212,7 @@
 
 #endif
 
-__initfunc(int acq_init(void))
+int __init acq_init(void)
 {
 	printk("WDT driver for Acquire single board computer initialising.\n");
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.3.9/linux/drivers/char/adbmouse.c	Mon Jun  7 12:12:22 1999
+++ linux/drivers/char/adbmouse.c	Tue Jul  6 19:16:55 1999
@@ -38,9 +38,7 @@
 #ifdef __powerpc__
 #include <asm/processor.h>
 #endif
-#ifdef __mc68000__
 #include <asm/setup.h>
-#endif
 
 static struct mouse_status mouse;
 static unsigned char adb_mouse_buttons[16];
@@ -244,7 +242,7 @@
     ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
 };
 
-__initfunc(int adb_mouse_init(void))
+int __init adb_mouse_init(void)
 {
     mouse.active = 0;
     mouse.ready = 0;
@@ -270,7 +268,7 @@
  * option, which is about using ADB keyboard buttons to emulate
  * mouse buttons. -- paulus
  */
-__initfunc(void adb_mouse_setup(char *str, int *ints))
+void __init adb_mouse_setup(char *str, int *ints)
 {
 	if (ints[0] >= 1) {
 		adb_emulate_buttons = ints[1] > 0;
@@ -282,7 +280,6 @@
 }
 
 #ifdef MODULE
-#include <asm/setup.h>
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.3.9/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- v2.3.9/linux/drivers/char/amigamouse.c	Mon Aug 24 13:02:43 1998
+++ linux/drivers/char/amigamouse.c	Tue Jul  6 19:16:55 1999
@@ -309,7 +309,7 @@
 	AMIGAMOUSE_MINOR, "amigamouse", &amiga_mouse_fops
 };
 
-__initfunc(int amiga_mouse_init(void))
+int __init amiga_mouse_init(void)
 {
 	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
 		return -ENODEV;
@@ -333,7 +333,6 @@
 }
 
 #ifdef MODULE
-#include <asm/setup.h>
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.3.9/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c
--- v2.3.9/linux/drivers/char/amikeyb.c	Mon Apr 26 13:25:54 1999
+++ linux/drivers/char/amikeyb.c	Tue Jul  6 19:16:55 1999
@@ -295,7 +295,7 @@
 	}
 }
 
-__initfunc(int amiga_keyb_init(void))
+int __init amiga_keyb_init(void)
 {
     if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
         return -EIO;
@@ -343,6 +343,6 @@
 }
 
 /* for "kbd-reset" cmdline param */
-__initfunc(void amiga_kbd_reset_setup(char *str, int *ints))
+void __init amiga_kbd_reset_setup(char *str, int *ints)
 {
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v2.3.9/linux/drivers/char/atarimouse.c	Mon Aug 24 13:02:43 1998
+++ linux/drivers/char/atarimouse.c	Tue Jul  6 19:16:55 1999
@@ -159,7 +159,7 @@
     ATARIMOUSE_MINOR, "atarimouse", &atari_mouse_fops
 };
 
-__initfunc(int atari_mouse_init(void))
+int __init atari_mouse_init(void)
 {
 	int r;
 
@@ -182,7 +182,7 @@
 #define	MIN_THRESHOLD 1
 #define	MAX_THRESHOLD 20	/* more seems not reasonable... */
 
-__initfunc(void atari_mouse_setup( char *str, int *ints ))
+void __init atari_mouse_setup( char *str, int *ints )
 {
     if (ints[0] < 1) {
 	printk( "atari_mouse_setup: no arguments!\n" );
diff -u --recursive --new-file v2.3.9/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v2.3.9/linux/drivers/char/atixlmouse.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/atixlmouse.c	Tue Jul  6 19:16:55 1999
@@ -202,7 +202,7 @@
 };
 
 
-__initfunc(int atixl_busmouse_init(void))
+int __init atixl_busmouse_init(void)
 {
 	unsigned char a,b,c;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.9/linux/drivers/char/bttv.c	Mon Jun  7 16:17:59 1999
+++ linux/drivers/char/bttv.c	Mon Jul  5 20:35:18 1999
@@ -43,7 +43,6 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
@@ -81,8 +80,8 @@
 #include "bttv.h"
 #include "tuner.h"
 
-#define DEBUG(x) 		/* Debug driver */	
-#define IDEBUG(x) 		/* Debug interrupt handler */
+#define DEBUG(x)		/* Debug driver */	
+#define IDEBUG(x)		/* Debug interrupt handler */
 
 #if LINUX_VERSION_CODE >= 0x020117
 MODULE_PARM(vidmem,"i");
@@ -110,7 +109,7 @@
 #define CARD_DEFAULT 0
 #endif
 
-static unsigned int remap[BTTV_MAX];    /* remap Bt848 */
+static unsigned long remap[BTTV_MAX];    /* remap Bt848 */
 static unsigned int radio[BTTV_MAX];
 static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, 
                                        CARD_DEFAULT, CARD_DEFAULT };
@@ -129,51 +128,80 @@
 #define EEPROM_WRITE_DELAY    20000
 #define BURSTOFFSET 76
 
-
-
 /*******************************/
 /* Memory management functions */
 /*******************************/
 
-/* convert virtual user memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
 
-static inline unsigned long uvirt_to_phys(unsigned long adr)
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
 {
-	pgd_t *pgd;
+        unsigned long ret = 0UL;
 	pmd_t *pmd;
 	pte_t *ptep, pte;
   
-	pgd = pgd_offset(current->mm, adr);
-	if (pgd_none(*pgd))
-		return 0;
-	pmd = pmd_offset(pgd, adr);
-	if (pmd_none(*pmd))
-		return 0;
-	ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
-	pte = *ptep;
-	if(pte_present(pte))
-		return 
-		  virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
-	return 0;
+	if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte))
+                                ret = (pte_page(pte)|(adr&(PAGE_SIZE-1)));
+                }
+        }
+        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+	return ret;
 }
 
 static inline unsigned long uvirt_to_bus(unsigned long adr) 
 {
-	return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
-}
+        unsigned long kva, ret;
 
-/* convert virtual kernel memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+	ret = virt_to_bus((void *)kva);
+        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+        return ret;
+}
 
-static inline unsigned long kvirt_to_phys(unsigned long adr) 
+static inline unsigned long kvirt_to_bus(unsigned long adr) 
 {
-	return uvirt_to_phys(VMALLOC_VMADDR(adr));
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = virt_to_bus((void *)kva);
+        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
+        return ret;
 }
 
-static inline unsigned long kvirt_to_bus(unsigned long adr) 
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-	return uvirt_to_bus(VMALLOC_VMADDR(adr));
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+        return ret;
 }
 
 static void * rvmalloc(unsigned long size)
@@ -188,8 +216,8 @@
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
-	                page = kvirt_to_phys(adr);
-			mem_map_reserve(MAP_NR(phys_to_virt(page)));
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(MAP_NR(__va(page)));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -206,8 +234,8 @@
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
-	                page = kvirt_to_phys(adr);
-			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(MAP_NR(__va(page)));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -541,13 +569,13 @@
         /* Aimslab VHX */
         { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
         /* Zoltrix TV-Max */
-        { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
+        { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}},
         /* Pixelview PlayTV (bt878) */
         { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
         /* "Leadtek WinView 601", */
         { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
         /* AVEC Intercapture */
-        { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
+        { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}},
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
 
@@ -823,30 +851,30 @@
 	unsigned int *po=(unsigned int *) btv->vbi_odd;
 	unsigned int *pe=(unsigned int *) btv->vbi_even;
   
-	DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd));
-	DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even));
-	DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
-	DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+	DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd));
+	DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even));
+	DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
+	DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
         
-	*(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0;
+	*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
 	for (i=0; i<16; i++) 
 	{
-		*(po++)=VBI_RISC;
-		*(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
+		*(po++)=cpu_to_le32(VBI_RISC);
+		*(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
 	}
-	*(po++)=BT848_RISC_JUMP;
-	*(po++)=virt_to_bus(btv->risc_jmp+4);
+	*(po++)=cpu_to_le32(BT848_RISC_JUMP);
+	*(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
-	*(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0;
+	*(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0;
 	for (i=16; i<32; i++) 
 	{
-		*(pe++)=VBI_RISC;
-		*(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
+		*(pe++)=cpu_to_le32(VBI_RISC);
+		*(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
 	}
-	*(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16);
-	*(pe++)=virt_to_bus(btv->risc_jmp+10);
-	DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
-	DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+	*(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16));
+	*(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
+	DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
+	DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
 }
 
 int fmtbppx2[16] = {
@@ -881,8 +909,8 @@
 	unsigned long bpl=1024;		/* bytes per line */
 	unsigned long vadr=(unsigned long) vbuf;
 
-	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
-	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
   
         /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
            is 2 and without separate VBI grabbing.
@@ -890,17 +918,17 @@
 
 	for (line=0; line < 640; line++)
 	{
-                *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
-                *(ro++)=kvirt_to_bus(vadr);
-                *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
-                *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2);
+                *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
+                *(ro++)=cpu_to_le32(kvirt_to_bus(vadr));
+                *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL);
+                *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2));
                 vadr+=bpl;
 	}
 	
-	*(ro++)=BT848_RISC_JUMP;
-	*(ro++)=btv->bus_vbi_even;
-	*(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
-	*(re++)=btv->bus_vbi_odd;
+	*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+	*(ro++)=cpu_to_le32(btv->bus_vbi_even);
+	*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
+	*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 	
 	return 0;
 }
@@ -954,8 +982,8 @@
 	cradr=cbadr+csize;
 	inter = (height>btv->win.cropheight/2) ? 1 : 0;
 	
-	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(ro++)=0;
-	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0;
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0;
   
 	for (line=0; line < (height<<(1^inter)); line++)
 	{
@@ -991,15 +1019,15 @@
 		 todo-=bl;
 		 if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */
 		 
-		 *((*rp)++)=rcmd|bl;
-		 *((*rp)++)=blcb|(blcr<<16);
-		 *((*rp)++)=kvirt_to_bus(vadr);
+		 *((*rp)++)=cpu_to_le32(rcmd|bl);
+		 *((*rp)++)=cpu_to_le32(blcb|(blcr<<16));
+		 *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 		 vadr+=bl;
 		 if((rcmd&(15<<28))==BT848_RISC_WRITE123)
 		 {
-		 	*((*rp)++)=kvirt_to_bus(cbadr);
+		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr));
 		 	cbadr+=blcb;
-		 	*((*rp)++)=kvirt_to_bus(cradr);
+		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr));
 		 	cradr+=blcr;
 		 }
 		 
@@ -1007,10 +1035,10 @@
 		}
 	}
 	
-	*(ro++)=BT848_RISC_JUMP;
-	*(ro++)=btv->bus_vbi_even;
-	*(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
-	*(re++)=btv->bus_vbi_odd;
+	*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+	*(ro++)=cpu_to_le32(btv->bus_vbi_even);
+	*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
+	*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 	
 	return 0;
 }
@@ -1037,8 +1065,8 @@
 	inter = (height>btv->win.cropheight/2) ? 1 : 0;
 	bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
 	
-	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
-	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
   
 	for (line=0; line < (height<<(1^inter)); line++)
 	{
@@ -1050,35 +1078,35 @@
 		bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
 		if (bpl<=bl)
                 {
-		        *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|
-			        BT848_RISC_EOL|bpl; 
-			*((*rp)++)=kvirt_to_bus(vadr);
+		        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+                                               BT848_RISC_EOL|bpl);
+			*((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 			vadr+=bpl;
 		}
 		else
 		{
 		        todo=bpl;
-		        *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl;
-			*((*rp)++)=kvirt_to_bus(vadr);
+		        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl);
+			*((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 			vadr+=bl;
 			todo-=bl;
 			while (todo>PAGE_SIZE)
 			{
-			        *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE;
-				*((*rp)++)=kvirt_to_bus(vadr);
+			        *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE);
+				*((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 				vadr+=PAGE_SIZE;
 				todo-=PAGE_SIZE;
 			}
-			*((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo;
-			*((*rp)++)=kvirt_to_bus(vadr);
+			*((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo);
+			*((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 			vadr+=todo;
 		}
 	}
 	
-	*(ro++)=BT848_RISC_JUMP;
-	*(ro++)=btv->bus_vbi_even;
-	*(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
-	*(re++)=btv->bus_vbi_odd;
+	*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+	*(ro++)=cpu_to_le32(btv->bus_vbi_even);
+	*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
+	*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 	
 	return 0;
 }
@@ -1162,10 +1190,10 @@
 	adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
 	if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
 		/* can't clip, don't generate any risc code */
-		*(ro++)=BT848_RISC_JUMP;
-		*(ro++)=btv->bus_vbi_even;
-		*(re++)=BT848_RISC_JUMP;
-		*(re++)=btv->bus_vbi_odd;
+		*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+		*(ro++)=cpu_to_le32(btv->bus_vbi_even);
+		*(re++)=cpu_to_le32(BT848_RISC_JUMP);
+		*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 	}
 	if (ncr < 0) {	/* bitmap was pased */
 		memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE);
@@ -1187,8 +1215,8 @@
 	if (btv->win.y<0)
 		clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
 	
-	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
-	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0;
+	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0;
 	
 	/* translate bitmap to risc code */
         for (line=outofmem=0; line < (height<<inter) && !outofmem; line++)
@@ -1206,10 +1234,10 @@
 				flags |= ((!sx) ? BT848_RISC_SOL : 0);
 				flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0);
 				if (!lastbit) {
-					*((*rp)++)=BT848_RISC_WRITE|flags|len;
-					*((*rp)++)=adr + bpp * sx;
+					*((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|flags|len);
+					*((*rp)++)=cpu_to_le32(adr + bpp * sx);
 				} else
-					*((*rp)++)=BT848_RISC_SKIP|flags|len;
+					*((*rp)++)=cpu_to_le32(BT848_RISC_SKIP|flags|len);
 				lastbit=cbit;
 				sx += dx;
 				dx = 1;
@@ -1224,10 +1252,10 @@
 	}
 	vfree(clipmap);
 	/* outofmem flag relies on the following code to discard extra data */
-	*(ro++)=BT848_RISC_JUMP;
-	*(ro++)=btv->bus_vbi_even;
-	*(re++)=BT848_RISC_JUMP;
-	*(re++)=btv->bus_vbi_odd;
+	*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
+	*(ro++)=cpu_to_le32(btv->bus_vbi_even);
+	*(re++)=cpu_to_le32(BT848_RISC_JUMP);
+	*(re++)=cpu_to_le32(btv->bus_vbi_odd);
 }
 
 /* set geometry for even/odd frames 
@@ -1297,6 +1325,23 @@
         set_pll(btv);
 
 	btwrite(fmt, BT848_COLOR_FMT);
+#ifdef __sparc__
+        if(fmt == BT848_COLOR_FMT_RGB32 ||
+           fmt == BT848_COLOR_FMT_RGB24) {
+                btwrite((BT848_COLOR_CTL_GAMMA		|
+                         BT848_COLOR_CTL_WSWAP_ODD	|
+                         BT848_COLOR_CTL_WSWAP_EVEN	|
+                         BT848_COLOR_CTL_BSWAP_ODD	|
+                         BT848_COLOR_CTL_BSWAP_EVEN),
+                        BT848_COLOR_CTL);
+        } else if(fmt == BT848_COLOR_FMT_RGB16 ||
+           fmt == BT848_COLOR_FMT_RGB15) {
+                btwrite((BT848_COLOR_CTL_GAMMA		|
+                         BT848_COLOR_CTL_BSWAP_ODD	|
+                         BT848_COLOR_CTL_BSWAP_EVEN),
+                        BT848_COLOR_CTL);
+        }
+#endif
 	hactive=width;
 
         vtc=0;
@@ -1474,7 +1519,7 @@
 			btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
 			btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
 		}
-		btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
+		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
 	btor(3, BT848_CAP_CTL);
 	btor(3, BT848_GPIO_DMA_CTL);
@@ -2268,7 +2313,7 @@
 	pos=(unsigned long) btv->fbuffer;
 	while (size > 0) 
 	{
-	        page = kvirt_to_phys(pos);
+	        page = kvirt_to_pa(pos);
 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
 		        return -EAGAIN;
 		start+=PAGE_SIZE;
@@ -3110,44 +3155,44 @@
 	int flags=btv->cap;
 
 	/* Sync to start of odd field */
-	btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE;
+	btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE);
 	btv->risc_jmp[1]=0;
 
 	/* Jump to odd vbi sub */
-	btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20);
+	btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20));
 	if (flags&8)
-		btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd);
+		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd));
 	else
-		btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4);
+		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
         /* Jump to odd sub */
-	btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20);
+	btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20));
 	if (flags&2)
-		btv->risc_jmp[5]=virt_to_bus(btv->risc_odd);
+		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd));
 	else
-		btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6);
+		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6));
 
 
 	/* Sync to start of even field */
-	btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO;
+	btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO);
 	btv->risc_jmp[7]=0;
 
 	/* Jump to even vbi sub */
-	btv->risc_jmp[8]=BT848_RISC_JUMP;
+	btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
 	if (flags&4)
-		btv->risc_jmp[9]=virt_to_bus(btv->vbi_even);
+		btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even));
 	else
-		btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10);
+		btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
 
 	/* Jump to even sub */
-	btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20);
+	btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20));
 	if (flags&1)
-		btv->risc_jmp[11]=virt_to_bus(btv->risc_even);
+		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even));
 	else
-		btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12);
+		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12));
 
-	btv->risc_jmp[12]=BT848_RISC_JUMP;
-	btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp);
+	btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
+	btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
 
 	/* enable capturing */
 	btaor(flags, ~0x0f, BT848_CAP_CTL);
@@ -3165,7 +3210,7 @@
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
-	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
+	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem));
 
 	/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
 	btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */
@@ -3330,8 +3375,7 @@
 		if (!astat)
 			return;
 		btwrite(astat,BT848_INT_STAT);
-		IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat));
-		IDEBUG(printk ("bttv%d:  stat %08x\n", btv->nr, stat));
+		IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat));
 
 		/* get device status bits */
 		dstat=btread(BT848_DSTATUS);
@@ -3387,8 +3431,8 @@
 					btv->gro = btv->gro_next;
 					btv->gre = btv->gre_next;
 					btv->grf = btv->grf_next;
-                                        btv->risc_jmp[5]=btv->gro;
-					btv->risc_jmp[11]=btv->gre;
+                                        btv->risc_jmp[5]=cpu_to_le32(btv->gro);
+					btv->risc_jmp[11]=cpu_to_le32(btv->gre);
 					bt848_set_geo(btv, btv->gwidth,
 						      btv->gheight,
 						      btv->gfmt);
@@ -3405,9 +3449,9 @@
 			}
 			if (stat&(8<<28)) 
 			{
-			        btv->risc_jmp[5]=btv->gro;
-				btv->risc_jmp[11]=btv->gre;
-				btv->risc_jmp[12]=BT848_RISC_JUMP;
+			        btv->risc_jmp[5]=cpu_to_le32(btv->gro);
+				btv->risc_jmp[11]=cpu_to_le32(btv->gre);
+				btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
 				bt848_set_geo(btv, btv->gwidth, btv->gheight,
 					      btv->gfmt);
 			}
@@ -3502,14 +3546,16 @@
 
         if (remap[bttv_num])
         {
+                unsigned int dw = btv->bt848_adr;
+
                 if (remap[bttv_num] < 0x1000)
                         remap[bttv_num]<<=20;
                 remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
-                printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n",
+                printk(KERN_INFO "bttv%d: remapping to : 0x%lx.\n",
                        bttv_num,remap[bttv_num]);
                 remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
                 pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
-                pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
+                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;
@@ -3518,7 +3564,7 @@
                bttv_num,btv->id, btv->revision);
         printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn);
         printk("irq: %d, ",btv->irq);
-        printk("memory: 0x%08x.\n", btv->bt848_adr);
+        printk("memory: 0x%lx.\n", btv->bt848_adr);
 
         btv->pll.pll_crystal = 0;
         btv->pll.pll_ifreq   = 0;
@@ -3542,7 +3588,11 @@
                 }
         }
         
+#ifdef __sparc__
+        btv->bt848_mem=(unsigned char *)btv->bt848_adr;
+#else
         btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+#endif
         
         /* clear interrupt mask */
 	btwrite(0, BT848_INT_MASK);
@@ -3817,17 +3867,17 @@
 		if (btv->risc_even)
 			kfree((void *) btv->risc_even);
 
-		DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp));
+		DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp));
 		if (btv->risc_jmp)
 			kfree((void *) btv->risc_jmp);
 
-		DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf));
+		DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf));
 		if (btv->vbibuf)
 			vfree((void *) btv->vbibuf);
 
 
 		free_irq(btv->irq,btv);
-		DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
+		DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem));
 		if (btv->bt848_mem)
 			iounmap(btv->bt848_mem);
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.3.9/linux/drivers/char/bttv.h	Mon Jun  7 16:17:59 1999
+++ linux/drivers/char/bttv.h	Mon Jul  5 20:07:02 1999
@@ -102,9 +102,9 @@
 #else
 	struct pci_dev *dev;
 #endif
-	unsigned char irq;          /* IRQ used by Bt848 card */
+	unsigned int irq;           /* IRQ used by Bt848 card */
 	unsigned char revision;
-	unsigned int bt848_adr;      /* bus address of IO mem returned by PCI BIOS */
+	unsigned long bt848_adr;    /* bus address of IO mem returned by PCI BIOS */
 	unsigned char *bt848_mem;   /* pointer to mapped IO memory */
 	unsigned long busriscmem; 
 	u32 *riscmem;
@@ -274,7 +274,7 @@
 #define TEA6320_S          0x07  /* switch register */
                                  /* values for those registers: */
 #define TEA6320_S_SA       0x01  /* stereo A input */
-#define TEA6320_S_SB       0x02  /* stereo B */
+#define TEA6320_S_SB       0x07  /* stereo B -- databook wrong? this works */
 #define TEA6320_S_SC       0x04  /* stereo C */
 #define TEA6320_S_GMU      0x80  /* general mute */
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.3.9/linux/drivers/char/busmouse.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/busmouse.c	Tue Jul  6 19:16:55 1999
@@ -60,7 +60,7 @@
 MODULE_PARM(mouse_irq, "i");
 #endif
 
-__initfunc(void bmouse_setup(char *str, int *ints))
+void __init bmouse_setup(char *str, int *ints)
 {
 	if (ints[0] > 0)
 		mouse_irq=ints[1];
@@ -252,7 +252,7 @@
 	LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
 };
 
-__initfunc(int bus_mouse_init(void))
+int __init bus_mouse_init(void)
 {
 	if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) {
 	  mouse.present = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/buz.c linux/drivers/char/buz.c
--- v2.3.9/linux/drivers/char/buz.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/buz.c	Tue Jul  6 10:11:40 1999
@@ -0,0 +1,3478 @@
+#define MAX_KMALLOC_MEM (512*1024)
+/*
+   buz - Iomega Buz driver version 1.0
+
+   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+   based on
+
+   buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   and
+
+   bttv - Bt848 frame grabber driver
+
+   Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+   & Marcus Metzler (mocm@thp.uni-koeln.de)
+
+   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/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <asm/spinlock.h>
+
+#include <linux/videodev.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include "buz.h"
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+
+#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ )
+#define GPIO_MASK 0xdf
+
+/*
+ 
+ BUZ
+ 
+   GPIO0 = 1, take board out of reset
+   GPIO1 = 1, take JPEG codec out of sleep mode
+   GPIO3 = 1, deassert FRAME# to 36060
+   
+
+   GIRQ0 signals a vertical sync of the video signal
+   GIRQ1 signals that ZR36060's DATERR# line is asserted.
+
+   SAA7111A
+
+   In their infinite wisdom, the Iomega engineers decided to
+   use the same input line for composite and S-Video Color,
+   although there are two entries not connected at all!
+   Through this ingenious strike, it is not possible to
+   keep two running video sources connected at the same time
+   to Composite and S-VHS input!
+
+   mode 0 - N/C
+   mode 1 - S-Video Y
+   mode 2 - noise or something I don't know
+   mode 3 - Composite and S-Video C
+   mode 4 - N/C
+   mode 5 - S-Video (gain C independently selectable of gain Y)
+   mode 6 - N/C
+   mode 7 - S-Video (gain C adapted to gain Y)
+ */
+
+#define MAJOR_VERSION 1		/* driver major version */
+#define MINOR_VERSION 0		/* driver minor version */
+
+#define BUZ_NAME      "Iomega BUZ V-1.0"	/* name of the driver */
+
+#define DEBUG(x)		/* Debug driver */
+#define IDEBUG(x)		/* Debug interrupt handler */
+#define IOCTL_DEBUG(x)
+
+
+/* The parameters for this driver */
+
+/*
+   The video mem address of the video card.
+   The driver has a little database for some videocards
+   to determine it from there. If your video card is not in there
+   you have either to give it to the driver as a parameter
+   or set in in a VIDIOCSFBUF ioctl
+ */
+
+static unsigned long vidmem = 0;	/* Video memory base address */
+
+/* Special purposes only: */
+
+static int triton = 0;		/* 0=no, 1=yes */
+static int natoma = 0;		/* 0=no, 1=yes */
+
+/*
+   Number and size of grab buffers for Video 4 Linux
+   The vast majority of applications should not need more than 2,
+   the very popular BTTV driver actually does ONLY have 2.
+   Time sensitive applications might need more, the maximum
+   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
+
+   The size is set so that the maximum possible request
+   can be satisfied. Decrease  it, if bigphys_area alloc'd
+   memory is low. If you don't have the bigphys_area patch,
+   set it to 128 KB. Will you allow only to grab small
+   images with V4L, but that's better than nothing.
+
+   v4l_bufsize has to be given in KB !
+
+ */
+
+static int v4l_nbufs = 2;
+static int v4l_bufsize = 128;	/* Everybody should be able to work with this setting */
+
+/*
+   Default input and video norm at startup of the driver.
+ */
+
+static int default_input = 0;	/* 0=Composite, 1=S-VHS */
+static int default_norm = 0;	/* 0=PAL, 1=NTSC */
+
+MODULE_PARM(vidmem, "i");
+MODULE_PARM(triton, "i");
+MODULE_PARM(natoma, "i");
+MODULE_PARM(v4l_nbufs, "i");
+MODULE_PARM(v4l_bufsize, "i");
+MODULE_PARM(default_input, "i");
+MODULE_PARM(default_norm, "i");
+
+/* Anybody who uses more than four? */
+#define BUZ_MAX 4
+
+static int zoran_num;		/* number of Buzs in use */
+static struct zoran zoran[BUZ_MAX];
+
+/* forward references */
+
+static void v4l_fbuffer_free(struct zoran *zr);
+static void jpg_fbuffer_free(struct zoran *zr);
+static void zoran_feed_stat_com(struct zoran *zr);
+
+
+
+/*
+ *   Allocate the V4L grab buffers
+ *
+ *   These have to be pysically contiguous.
+ *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
+ */
+
+static int v4l_fbuffer_alloc(struct zoran *zr)
+{
+	int i, off;
+	unsigned char *mem;
+
+	for (i = 0; i < v4l_nbufs; i++) {
+		if (zr->v4l_gbuf[i].fbuffer)
+			printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i);
+
+		if (v4l_bufsize <= MAX_KMALLOC_MEM) {
+			/* Use kmalloc */
+
+			mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL);
+			if (mem == 0) {
+				printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name);
+				v4l_fbuffer_free(zr);
+				return -ENOBUFS;
+			}
+			zr->v4l_gbuf[i].fbuffer = mem;
+			zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
+			zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
+			for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
+				mem_map_reserve(MAP_NR(mem + off));
+			DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem)));
+		} else {
+			return -ENOBUFS;
+		}
+	}
+
+	return 0;
+}
+
+/* free the V4L grab buffers */
+static void v4l_fbuffer_free(struct zoran *zr)
+{
+	int i, off;
+	unsigned char *mem;
+
+	for (i = 0; i < v4l_nbufs; i++) {
+		if (!zr->v4l_gbuf[i].fbuffer)
+			continue;
+
+		mem = zr->v4l_gbuf[i].fbuffer;
+		for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
+			mem_map_unreserve(MAP_NR(mem + off));
+		kfree((void *) zr->v4l_gbuf[i].fbuffer);
+		zr->v4l_gbuf[i].fbuffer = NULL;
+	}
+}
+
+/*
+ *   Allocate the MJPEG grab buffers.
+ *
+ *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
+ *   kmalloc is used to request a physically contiguous area,
+ *   else we allocate the memory in framgents with get_free_page.
+ *
+ *   If a Natoma chipset is present and this is a revision 1 zr36057,
+ *   each MJPEG buffer needs to be physically contiguous.
+ *   (RJ: This statement is from Dave Perks' original driver,
+ *   I could never check it because I have a zr36067)
+ *   The driver cares about this because it reduces the buffer
+ *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
+ *
+ *   RJ: The contents grab buffers needs never be accessed in the driver.
+ *       Therefore there is no need to allocate them with vmalloc in order
+ *       to get a contiguous virtual memory space.
+ *       I don't understand why many other drivers first allocate them with
+ *       vmalloc (which uses internally also get_free_page, but delivers you
+ *       virtual addresses) and then again have to make a lot of efforts
+ *       to get the physical address.
+ *
+ */
+
+static int jpg_fbuffer_alloc(struct zoran *zr)
+{
+	int i, j, off, alloc_contig;
+	unsigned long mem;
+
+	/* Decide if we should alloc contiguous or fragmented memory */
+	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
+
+	alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM);
+
+	for (i = 0; i < zr->jpg_nbufs; i++) {
+		if (zr->jpg_gbuf[i].frag_tab)
+			printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i);
+
+		/* Allocate fragment table for this buffer */
+
+		mem = get_free_page(GFP_KERNEL);
+		if (mem == 0) {
+			printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i);
+			jpg_fbuffer_free(zr);
+			return -ENOBUFS;
+		}
+		memset((void *) mem, 0, PAGE_SIZE);
+		zr->jpg_gbuf[i].frag_tab = (u32 *) mem;
+		zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem);
+
+		if (alloc_contig) {
+			mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL);
+			if (mem == 0) {
+				jpg_fbuffer_free(zr);
+				return -ENOBUFS;
+			}
+			zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem);
+			zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1;
+			for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
+				mem_map_reserve(MAP_NR(mem + off));
+		} else {
+			/* jpg_bufsize is alreay page aligned */
+			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+				mem = get_free_page(GFP_KERNEL);
+				if (mem == 0) {
+					jpg_fbuffer_free(zr);
+					return -ENOBUFS;
+				}
+				zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem);
+				zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1;
+				mem_map_reserve(MAP_NR(mem));
+			}
+
+			zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1;
+		}
+	}
+
+	DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n",
+		     (zr->jpg_nbufs * zr->jpg_bufsize) >> 10));
+	zr->jpg_buffers_allocated = 1;
+	return 0;
+}
+
+/* free the MJPEG grab buffers */
+static void jpg_fbuffer_free(struct zoran *zr)
+{
+	int i, j, off, alloc_contig;
+	unsigned char *mem;
+
+	/* Decide if we should alloc contiguous or fragmented memory */
+	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
+
+	alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM);
+
+	for (i = 0; i < zr->jpg_nbufs; i++) {
+		if (!zr->jpg_gbuf[i].frag_tab)
+			continue;
+
+		if (alloc_contig) {
+			if (zr->jpg_gbuf[i].frag_tab[0]) {
+				mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]);
+				for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
+					mem_map_unreserve(MAP_NR(mem + off));
+				kfree((void *) mem);
+				zr->jpg_gbuf[i].frag_tab[0] = 0;
+				zr->jpg_gbuf[i].frag_tab[1] = 0;
+			}
+		} else {
+			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+				if (!zr->jpg_gbuf[i].frag_tab[2 * j])
+					break;
+				mem_map_unreserve(MAP_NR(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])));
+				free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]));
+				zr->jpg_gbuf[i].frag_tab[2 * j] = 0;
+				zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0;
+			}
+		}
+
+		free_page((unsigned long) zr->jpg_gbuf[i].frag_tab);
+		zr->jpg_gbuf[i].frag_tab = NULL;
+	}
+	zr->jpg_buffers_allocated = 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/* I2C functions                                                           */
+
+#define I2C_DELAY   10
+
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data)
+{
+	struct zoran *zr = (struct zoran *) bus->data;
+	btwrite((data << 1) | ctrl, ZR36057_I2CBR);
+	btread(ZR36057_I2CBR);
+	udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+	struct zoran *zr = (struct zoran *) bus->data;
+	return (btread(ZR36057_I2CBR) >> 1) & 1;
+}
+
+void attach_inform(struct i2c_bus *bus, int id)
+{
+	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
+	DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
+}
+
+void detach_inform(struct i2c_bus *bus, int id)
+{
+	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
+	DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
+}
+
+static struct i2c_bus zoran_i2c_bus_template =
+{
+	"zr36057",
+	I2C_BUSID_BT848,
+	NULL,
+
+	SPIN_LOCK_UNLOCKED,
+
+	attach_inform,
+	detach_inform,
+
+	i2c_setlines,
+	i2c_getdataline,
+	NULL,
+	NULL,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+static void GPIO(struct zoran *zr, unsigned bit, unsigned value)
+{
+	u32 reg;
+	u32 mask;
+
+	mask = 1 << (24 + bit);
+	reg = btread(ZR36057_GPPGCR1) & ~mask;
+	if (value) {
+		reg |= mask;
+	}
+	btwrite(reg, ZR36057_GPPGCR1);
+	/* Stop any PCI posting on the GPIO bus */
+	btread(ZR36057_I2CBR);
+}
+
+
+/*
+ *   Set the registers for the size we have specified. Don't bother
+ *   trying to understand this without the ZR36057 manual in front of
+ *   you [AC].
+ *
+ *   PS: The manual is free for download in .pdf format from
+ *   www.zoran.com - nicely done those folks.
+ */
+
+struct tvnorm {
+	u16 Wt, Wa, Ht, Ha, HStart, VStart;
+};
+
+static struct tvnorm tvnorms[] =
+{
+   /* PAL-BDGHI */
+	{864, 720, 625, 576, 31, 16},
+   /* NTSC */
+	{858, 720, 525, 480, 21, 8},
+};
+#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm))
+
+static int format2bpp(int format)
+{
+	int bpp;
+
+	/* Determine the number of bytes per pixel for the video format requested */
+
+	switch (format) {
+
+	case VIDEO_PALETTE_YUV422:
+		bpp = 2;
+		break;
+
+	case VIDEO_PALETTE_RGB555:
+		bpp = 2;
+		break;
+
+	case VIDEO_PALETTE_RGB565:
+		bpp = 2;
+		break;
+
+	case VIDEO_PALETTE_RGB24:
+		bpp = 3;
+		break;
+
+	case VIDEO_PALETTE_RGB32:
+		bpp = 4;
+		break;
+
+	default:
+		bpp = 0;
+	}
+
+	return bpp;
+}
+
+/*
+ * set geometry
+ */
+static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height,
+			    unsigned int video_format)
+{
+	struct tvnorm *tvn;
+	unsigned HStart, HEnd, VStart, VEnd;
+	unsigned DispMode;
+	unsigned VidWinWid, VidWinHt;
+	unsigned hcrop1, hcrop2, vcrop1, vcrop2;
+	unsigned Wa, We, Ha, He;
+	unsigned X, Y, HorDcm, VerDcm;
+	u32 reg;
+	unsigned mask_line_size;
+
+	if (zr->params.norm < 0 || zr->params.norm > 1) {
+		printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name,  zr->params.norm);
+		return;
+	}
+	if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) {
+		printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height);
+		return;
+	}
+	tvn = &tvnorms[zr->params.norm];
+
+	Wa = tvn->Wa;
+	Ha = tvn->Ha;
+
+	/* if window has more than half of active height,
+	   switch on interlacing - we want the full information */
+
+	zr->video_interlace = (video_height > Ha / 2);
+
+/**** zr36057 ****/
+
+	/* horizontal */
+	VidWinWid = video_width;
+	X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
+	We = (VidWinWid * 64) / X;
+	HorDcm = 64 - X;
+	hcrop1 = 2 * ((tvn->Wa - We) / 4);
+	hcrop2 = tvn->Wa - We - hcrop1;
+	HStart = tvn->HStart | 1;
+	HEnd = HStart + tvn->Wa - 1;
+	HStart += hcrop1;
+	HEnd -= hcrop2;
+	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
+	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
+	reg |= ZR36057_VFEHCR_HSPol;
+	btwrite(reg, ZR36057_VFEHCR);
+
+	/* Vertical */
+	DispMode = !zr->video_interlace;
+	VidWinHt = DispMode ? video_height : video_height / 2;
+	Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
+	He = (VidWinHt * 64) / Y;
+	VerDcm = 64 - Y;
+	vcrop1 = (tvn->Ha / 2 - He) / 2;
+	vcrop2 = tvn->Ha / 2 - He - vcrop1;
+	VStart = tvn->VStart;
+	VEnd = VStart + tvn->Ha / 2 - 1;
+	VStart += vcrop1;
+	VEnd -= vcrop2;
+	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
+	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
+	reg |= ZR36057_VFEVCR_VSPol;
+	btwrite(reg, ZR36057_VFEVCR);
+
+	/* scaler and pixel format */
+	reg = 0			// ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */
+	     | (HorDcm << ZR36057_VFESPFR_HorDcm)
+	    | (VerDcm << ZR36057_VFESPFR_VerDcm)
+	    | (DispMode << ZR36057_VFESPFR_DispMode)
+	    | ZR36057_VFESPFR_LittleEndian;
+	/* RJ: I don't know, why the following has to be the opposite
+	   of the corresponding ZR36060 setting, but only this way
+	   we get the correct colors when uncompressing to the screen  */
+	reg |= ZR36057_VFESPFR_VCLKPol;
+	/* RJ: Don't know if that is needed for NTSC also */
+	reg |= ZR36057_VFESPFR_TopField;
+	switch (video_format) {
+
+	case VIDEO_PALETTE_YUV422:
+		reg |= ZR36057_VFESPFR_YUV422;
+		break;
+
+	case VIDEO_PALETTE_RGB555:
+		reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
+		break;
+
+	case VIDEO_PALETTE_RGB565:
+		reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
+		break;
+
+	case VIDEO_PALETTE_RGB24:
+		reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
+		break;
+
+	case VIDEO_PALETTE_RGB32:
+		reg |= ZR36057_VFESPFR_RGB888;
+		break;
+
+	default:
+		printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format);
+		return;
+
+	}
+	if (HorDcm >= 48) {
+		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
+	} else if (HorDcm >= 32) {
+		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */
+	} else if (HorDcm >= 16) {
+		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
+	}
+	btwrite(reg, ZR36057_VFESPFR);
+
+	/* display configuration */
+
+	reg = (16 << ZR36057_VDCR_MinPix)
+	    | (VidWinHt << ZR36057_VDCR_VidWinHt)
+	    | (VidWinWid << ZR36057_VDCR_VidWinWid);
+	if (triton)
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+
+	/* Write overlay clipping mask data, but don't enable overlay clipping */
+	/* RJ: since this makes only sense on the screen, we use 
+	   zr->window.width instead of video_width */
+
+	mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+	reg = virt_to_bus(zr->overlay_mask);
+	btwrite(reg, ZR36057_MMTR);
+	reg = virt_to_bus(zr->overlay_mask + mask_line_size);
+	btwrite(reg, ZR36057_MMBR);
+	reg = mask_line_size - (zr->window.width + 31) / 32;
+	if (DispMode == 0)
+		reg += mask_line_size;
+	reg <<= ZR36057_OCR_MaskStride;
+	btwrite(reg, ZR36057_OCR);
+
+}
+
+/*
+ * Switch overlay on or off
+ */
+
+static void zr36057_overlay(struct zoran *zr, int on)
+{
+	int fmt, bpp;
+	u32 reg;
+
+	if (on) {
+		/* do the necessary settings ... */
+
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */
+
+		switch (zr->buffer.depth) {
+		case 15:
+			fmt = VIDEO_PALETTE_RGB555;
+			bpp = 2;
+			break;
+		case 16:
+			fmt = VIDEO_PALETTE_RGB565;
+			bpp = 2;
+			break;
+		case 24:
+			fmt = VIDEO_PALETTE_RGB24;
+			bpp = 3;
+			break;
+		case 32:
+			fmt = VIDEO_PALETTE_RGB32;
+			bpp = 4;
+			break;
+		default:
+			fmt = 0;
+			bpp = 0;
+		}
+
+		zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt);
+
+		/* Start and length of each line MUST be 4-byte aligned.
+		   This should be allready checked before the call to this routine.
+		   All error messages are internal driver checking only! */
+
+		/* video display top and bottom registers */
+
+		reg = (u32) zr->buffer.base
+		    + zr->window.x * bpp
+		    + zr->window.y * zr->buffer.bytesperline;
+		btwrite(reg, ZR36057_VDTR);
+		if (reg & 3)
+			printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name);
+		if (zr->video_interlace)
+			reg += zr->buffer.bytesperline;
+		btwrite(reg, ZR36057_VDBR);
+
+		/* video stride, status, and frame grab register */
+
+		reg = zr->buffer.bytesperline - zr->window.width * bpp;
+		if (zr->video_interlace)
+			reg += zr->buffer.bytesperline;
+		if (reg & 3)
+			printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name);
+		reg = (reg << ZR36057_VSSFGR_DispStride);
+		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */
+		btwrite(reg, ZR36057_VSSFGR);
+
+		/* Set overlay clipping */
+
+		if (zr->window.clipcount)
+			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
+
+		/* ... and switch it on */
+
+		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	} else {
+		/* Switch it off */
+
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	}
+}
+
+/*
+ * The overlay mask has one bit for each pixel on a scan line,
+ *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
+ */
+static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count)
+{
+	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+	u32 *mask;
+	int x, y, width, height;
+	unsigned i, j, k;
+	u32 reg;
+
+	/* fill mask with one bits */
+	memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
+	reg = 0;
+
+	for (i = 0; i < count; ++i) {
+		/* pick up local copy of clip */
+		x = vp[i].x;
+		y = vp[i].y;
+		width = vp[i].width;
+		height = vp[i].height;
+
+		/* trim clips that extend beyond the window */
+		if (x < 0) {
+			width += x;
+			x = 0;
+		}
+		if (y < 0) {
+			height += y;
+			y = 0;
+		}
+		if (x + width > zr->window.width) {
+			width = zr->window.width - x;
+		}
+		if (y + height > zr->window.height) {
+			height = zr->window.height - y;
+		}
+		/* ignore degenerate clips */
+		if (height <= 0) {
+			continue;
+		}
+		if (width <= 0) {
+			continue;
+		}
+		/* apply clip for each scan line */
+		for (j = 0; j < height; ++j) {
+			/* reset bit for each pixel */
+			/* this can be optimized later if need be */
+			mask = zr->overlay_mask + (y + j) * mask_line_size;
+			for (k = 0; k < width; ++k) {
+				mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32);
+			}
+		}
+	}
+}
+
+/* Enable/Disable uncompressed memory grabbing of the 36057 */
+
+static void zr36057_set_memgrab(struct zoran *zr, int mode)
+{
+	if (mode) {
+		if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
+			printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name);
+
+		/* switch on VSync interrupts */
+
+		btwrite(IRQ_MASK, ZR36057_ISR);		// Clear Interrupts
+
+		btor(ZR36057_ICR_GIRQ0, ZR36057_ICR);
+
+		/* enable SnapShot */
+
+		btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+
+		/* Set zr36057 video front end  and enable video */
+
+#ifdef XAWTV_HACK
+		zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat);
+#else
+		zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat);
+#endif
+
+		zr->v4l_memgrab_active = 1;
+	} else {
+		zr->v4l_memgrab_active = 0;
+
+		/* switch off VSync interrupts */
+
+		btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR);
+
+		/* reenable grabbing to screen if it was running */
+
+		if (zr->v4l_overlay_active) {
+			zr36057_overlay(zr, 1);
+		} else {
+			btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+			btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+		}
+	}
+}
+
+static int wait_grab_pending(struct zoran *zr)
+{
+	unsigned long flags;
+
+	/* wait until all pending grabs are finished */
+
+	if (!zr->v4l_memgrab_active)
+		return 0;
+
+	while (zr->v4l_pend_tail != zr->v4l_pend_head) {
+		interruptible_sleep_on(&zr->v4l_capq);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	spin_lock_irqsave(&zr->lock, flags);
+	zr36057_set_memgrab(zr, 0);
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return 0;
+}
+
+/*
+ *   V4L Buffer grabbing
+ */
+
+static int v4l_grab(struct zoran *zr, struct video_mmap *mp)
+{
+	unsigned long flags;
+	int res, bpp;
+
+	/*
+	 * There is a long list of limitations to what is allowed to be grabbed
+	 * We don't output error messages her, since some programs (e.g. xawtv)
+	 * just try several settings to find out what is valid or not.
+	 */
+
+	/* No grabbing outside the buffer range! */
+
+	if (mp->frame >= v4l_nbufs || mp->frame < 0)
+		return -EINVAL;
+
+	/* Check size and format of the grab wanted */
+
+	if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH)
+		return -EINVAL;
+	if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH)
+		return -EINVAL;
+
+	bpp = format2bpp(mp->format);
+	if (bpp == 0)
+		return -EINVAL;
+
+	/* Check against available buffer size */
+
+	if (mp->height * mp->width * bpp > v4l_bufsize)
+		return -EINVAL;
+
+	/* The video front end needs 4-byte alinged line sizes */
+
+	if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3)))
+		return -EINVAL;
+
+	/*
+	 * To minimize the time spent in the IRQ routine, we avoid setting up
+	 * the video front end there.
+	 * If this grab has different parameters from a running streaming capture
+	 * we stop the streaming capture and start it over again.
+	 */
+
+	if (zr->v4l_memgrab_active &&
+	    (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) {
+		res = wait_grab_pending(zr);
+		if (res)
+			return res;
+	}
+	zr->gwidth = mp->width;
+	zr->gheight = mp->height;
+	zr->gformat = mp->format;
+	zr->gbpl = bpp * zr->gwidth;
+
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	/* make sure a grab isn't going on currently with this buffer */
+
+	switch (zr->v4l_gbuf[mp->frame].state) {
+
+	default:
+	case BUZ_STATE_PEND:
+		res = -EBUSY;	/* what are you doing? */
+		break;
+
+	case BUZ_STATE_USER:
+	case BUZ_STATE_DONE:
+		/* since there is at least one unused buffer there's room for at least one more pend[] entry */
+		zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame;
+		zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND;
+		res = 0;
+		break;
+
+	}
+
+	/* put the 36057 into frame grabbing mode */
+
+	if (!res && !zr->v4l_memgrab_active)
+		zr36057_set_memgrab(zr, 1);
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return res;
+}
+
+/*
+ * Sync on a V4L buffer
+ */
+
+static int v4l_sync(struct zoran *zr, int frame)
+{
+	unsigned long flags;
+
+
+	/* check passed-in frame number */
+	if (frame >= v4l_nbufs || frame < 0) {
+		printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame);
+		return -EINVAL;
+	}
+	/* Check if is buffer was queued at all */
+
+	if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) {
+//		printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name);
+		return -EINVAL;
+	}
+	/* wait on this buffer to get ready */
+
+	while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) {
+		interruptible_sleep_on(&zr->v4l_capq);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	/* buffer should now be in BUZ_STATE_DONE */
+
+	if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE)
+		printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name);
+
+	/* Check if streaming capture has finished */
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	if (zr->v4l_pend_tail == zr->v4l_pend_head)
+		zr36057_set_memgrab(zr, 0);
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return 0;
+}
+/*****************************************************************************
+ *                                                                           *
+ *  Set up the Buz-specific MJPEG part                                       *
+ *                                                                           *
+ *****************************************************************************/
+
+/*
+ *	Wait til post office is no longer busy 
+ */
+ 
+static int post_office_wait(struct zoran *zr)
+{
+	u32 por;
+	u32 ct=0;
+
+	while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
+		ct++;
+		if(ct>100000)
+		{
+			printk(KERN_ERR "%s: timeout on post office.\n", zr->name);
+			return -1;
+		}
+		/* wait for something to happen */
+	}
+	if ((por & ZR36057_POR_POPen) != 0) {
+		printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por);
+		return -1;
+	}
+	if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) {
+		printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por);
+		return -1;
+	}
+	return 0;
+}
+
+static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value)
+{
+	u32 por;
+
+	post_office_wait(zr);
+	por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF);
+	btwrite(por, ZR36057_POR);
+	return post_office_wait(zr);
+}
+
+static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg)
+{
+	u32 por;
+
+	post_office_wait(zr);
+	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
+	btwrite(por, ZR36057_POR);
+	if (post_office_wait(zr) < 0) {
+		return -1;
+	}
+	return btread(ZR36057_POR) & 0xFF;
+}
+
+static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg)) {
+		return -1;
+	}
+	return post_office_write(zr, 0, 3, val);
+}
+
+static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (zr36060_write_8(zr, reg + 0, val >> 8)) {
+		return -1;
+	}
+	return zr36060_write_8(zr, reg + 1, val >> 0);
+}
+
+static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (zr36060_write_8(zr, reg + 0, val >> 16)) {
+		return -1;
+	}
+	return zr36060_write_16(zr, reg + 1, val >> 0);
+}
+
+static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (zr36060_write_16(zr, reg + 0, val >> 16)) {
+		return -1;
+	}
+	return zr36060_write_16(zr, reg + 2, val >> 0);
+}
+
+static u32 zr36060_read_8(struct zoran *zr, unsigned reg)
+{
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg)) {
+		return -1;
+	}
+	return post_office_read(zr, 0, 3) & 0xFF;
+}
+
+static int zr36060_reset(struct zoran *zr)
+{
+	return post_office_write(zr, 3, 0, 0);
+}
+
+static void zr36060_sleep(struct zoran *zr, int sleep)
+{
+	GPIO(zr, 1, !sleep);
+}
+
+
+static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+	int size;
+
+	reg = (1 << 0)		/* CodeMstr */
+	    |(0 << 2)		/* CFIS=0 */
+	    |(0 << 6)		/* Endian=0 */
+	    |(0 << 7);		/* Code16=0 */
+	zr36060_write_8(zr, 0x002, reg);
+
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+	case BUZ_MODE_STILL_DECOMPRESS:
+		reg = 0x00;	/* Codec mode = decompression */
+		break;
+
+	case BUZ_MODE_MOTION_COMPRESS:
+	case BUZ_MODE_STILL_COMPRESS:
+	default:
+		reg = 0xa4;	/* Codec mode = compression with variable scale factor */
+		break;
+
+	}
+	zr36060_write_8(zr, 0x003, reg);
+
+	reg = 0x00;		/* reserved, mbz */
+	zr36060_write_8(zr, 0x004, reg);
+
+	reg = 0xff;		/* 510 bits/block */
+	zr36060_write_8(zr, 0x005, reg);
+
+	/* JPEG markers */
+	reg = (zr->params.jpeg_markers) & 0x38;	/* DRI, DQT, DHT */
+	if (zr->params.COM_len)
+		reg |= JPEG_MARKER_COM;
+	if (zr->params.APP_len)
+		reg |= JPEG_MARKER_APP;
+	zr36060_write_8(zr, 0x006, reg);
+
+	reg = (0 << 3)		/* DATERR=0 */
+	    |(0 << 2)		/* END=0 */
+	    |(0 << 1)		/* EOI=0 */
+	    |(0 << 0);		/* EOAV=0 */
+	zr36060_write_8(zr, 0x007, reg);
+
+	/* code volume */
+
+	/* Target field size in pixels: */
+	tvn = &tvnorms[zr->params.norm];
+	size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm);
+
+	/* Target compressed field size in bits: */
+	size = size * 16;	/* uncompressed size in bits */
+	size = size * zr->params.quality / 400;	/* quality = 100 is a compression ratio 1:4 */
+
+	/* Lower limit (arbitrary, 1 KB) */
+	if (size < 8192)
+		size = 8192;
+
+	/* Upper limit: 7/8 of the code buffers */
+	if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7)
+		size = zr->jpg_bufsize * 7 / zr->params.field_per_buff;
+
+	reg = size;
+	zr36060_write_32(zr, 0x009, reg);
+
+	/* how do we set initial SF as a function of quality parameter? */
+	reg = 0x0100;		/* SF=1.0 */
+	zr36060_write_16(zr, 0x011, reg);
+
+	reg = 0x00ffffff;	/* AF=max */
+	zr36060_write_24(zr, 0x013, reg);
+
+	reg = 0x0000;		/* test */
+	zr36060_write_16(zr, 0x024, reg);
+}
+
+static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+
+	reg = (0 << 7)		/* Video8=0 */
+	    |(0 << 6)		/* Range=0 */
+	    |(0 << 3)		/* FlDet=0 */
+	    |(1 << 2)		/* FlVedge=1 */
+	    |(0 << 1)		/* FlExt=0 */
+	    |(0 << 0);		/* SyncMstr=0 */
+
+	/* According to ZR36067 documentation, FlDet should correspond
+	   to the odd_even flag of the ZR36067 */
+	if (zr->params.odd_even)
+		reg |= (1 << 3);
+
+	if (mode != BUZ_MODE_STILL_DECOMPRESS) {
+		/* limit pixels to range 16..235 as per CCIR-601 */
+		reg |= (1 << 6);	/* Range=1 */
+	}
+	zr36060_write_8(zr, 0x030, reg);
+
+	reg = (0 << 7)		/* VCLKPol=0 */
+	    |(0 << 6)		/* PValPol=0 */
+	    |(1 << 5)		/* PoePol=1 */
+	    |(0 << 4)		/* SImgPol=0 */
+	    |(0 << 3)		/* BLPol=0 */
+	    |(0 << 2)		/* FlPol=0 */
+	    |(0 << 1)		/* HSPol=0, sync on falling edge */
+	    |(1 << 0);		/* VSPol=1 */
+	zr36060_write_8(zr, 0x031, reg);
+
+	switch (zr->params.HorDcm) {
+	default:
+	case 1:
+		reg = (0 << 0);
+		break;		/* HScale = 0 */
+
+	case 2:
+		reg = (1 << 0);
+		break;		/* HScale = 1 */
+
+	case 4:
+		reg = (2 << 0);
+		break;		/* HScale = 2 */
+	}
+	if (zr->params.VerDcm == 2)
+		reg |= (1 << 2);
+	zr36060_write_8(zr, 0x032, reg);
+
+	reg = 0x80;		/* BackY */
+	zr36060_write_8(zr, 0x033, reg);
+
+	reg = 0xe0;		/* BackU */
+	zr36060_write_8(zr, 0x034, reg);
+
+	reg = 0xe0;		/* BackV */
+	zr36060_write_8(zr, 0x035, reg);
+
+	/* sync generator */
+
+	tvn = &tvnorms[zr->params.norm];
+
+	reg = tvn->Ht - 1;	/* Vtotal */
+	zr36060_write_16(zr, 0x036, reg);
+
+	reg = tvn->Wt - 1;	/* Htotal */
+	zr36060_write_16(zr, 0x038, reg);
+
+	reg = 6 - 1;		/* VsyncSize */
+	zr36060_write_8(zr, 0x03a, reg);
+
+	reg = 100 - 1;		/* HsyncSize */
+	zr36060_write_8(zr, 0x03b, reg);
+
+	reg = tvn->VStart - 1;	/* BVstart */
+	zr36060_write_8(zr, 0x03c, reg);
+
+	reg += tvn->Ha / 2;	/* BVend */
+	zr36060_write_16(zr, 0x03e, reg);
+
+	reg = tvn->HStart - 1;	/* BHstart */
+	zr36060_write_8(zr, 0x03d, reg);
+
+	reg += tvn->Wa;		/* BHend */
+	zr36060_write_16(zr, 0x040, reg);
+
+	/* active area */
+	reg = zr->params.img_y + tvn->VStart;	/* Vstart */
+	zr36060_write_16(zr, 0x042, reg);
+
+	reg += zr->params.img_height;	/* Vend */
+	zr36060_write_16(zr, 0x044, reg);
+
+	reg = zr->params.img_x + tvn->HStart;	/* Hstart */
+	zr36060_write_16(zr, 0x046, reg);
+
+	reg += zr->params.img_width;	/* Hend */
+	zr36060_write_16(zr, 0x048, reg);
+
+	/* subimage area */
+	reg = zr->params.img_y + tvn->VStart;	/* SVstart */
+	zr36060_write_16(zr, 0x04a, reg);
+
+	reg += zr->params.img_height;	/* SVend */
+	zr36060_write_16(zr, 0x04c, reg);
+
+	reg = zr->params.img_x + tvn->HStart;	/* SHstart */
+	zr36060_write_16(zr, 0x04e, reg);
+
+	reg += zr->params.img_width;	/* SHend */
+	zr36060_write_16(zr, 0x050, reg);
+}
+
+static void zr36060_set_jpg_SOF(struct zoran *zr)
+{
+	u32 reg;
+
+
+	reg = 0xffc0;		/* SOF marker */
+	zr36060_write_16(zr, 0x060, reg);
+
+	reg = 17;		/* SOF length */
+	zr36060_write_16(zr, 0x062, reg);
+
+	reg = 8;		/* precision 8 bits */
+	zr36060_write_8(zr, 0x064, reg);
+
+	reg = zr->params.img_height / zr->params.VerDcm;	/* image height */
+	zr36060_write_16(zr, 0x065, reg);
+
+	reg = zr->params.img_width / zr->params.HorDcm;	/* image width */
+	zr36060_write_16(zr, 0x067, reg);
+
+	reg = 3;		/* 3 color components */
+	zr36060_write_8(zr, 0x069, reg);
+
+	reg = 0x002100;		/* Y component */
+	zr36060_write_24(zr, 0x06a, reg);
+
+	reg = 0x011101;		/* U component */
+	zr36060_write_24(zr, 0x06d, reg);
+
+	reg = 0x021101;		/* V component */
+	zr36060_write_24(zr, 0x070, reg);
+}
+
+static void zr36060_set_jpg_SOS(struct zoran *zr)
+{
+	u32 reg;
+
+
+	reg = 0xffda;		/* SOS marker */
+	zr36060_write_16(zr, 0x07a, reg);
+
+	reg = 12;		/* SOS length */
+	zr36060_write_16(zr, 0x07c, reg);
+
+	reg = 3;		/* 3 color components */
+	zr36060_write_8(zr, 0x07e, reg);
+
+	reg = 0x0000;		/* Y component */
+	zr36060_write_16(zr, 0x07f, reg);
+
+	reg = 0x0111;		/* U component */
+	zr36060_write_16(zr, 0x081, reg);
+
+	reg = 0x0211;		/* V component */
+	zr36060_write_16(zr, 0x083, reg);
+
+	reg = 0x003f00;		/* Start, end spectral scans */
+	zr36060_write_24(zr, 0x085, reg);
+}
+
+static void zr36060_set_jpg_DRI(struct zoran *zr)
+{
+	u32 reg;
+
+
+	reg = 0xffdd;		/* DRI marker */
+	zr36060_write_16(zr, 0x0c0, reg);
+
+	reg = 4;		/* DRI length */
+	zr36060_write_16(zr, 0x0c2, reg);
+
+	reg = 8;		/* length in MCUs */
+	zr36060_write_16(zr, 0x0c4, reg);
+}
+
+static void zr36060_set_jpg_DQT(struct zoran *zr)
+{
+	unsigned i;
+	unsigned adr;
+	static const u8 dqt[] =
+	{
+		0xff, 0xdb,	/* DHT marker */
+		0x00, 0x84,	/* DHT length */
+		0x00,		/* table ID 0 */
+		0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+		0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+		0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+		0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+		0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+		0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+		0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+		0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+		0x01,		/* table ID 1 */
+		0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+		0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+	};
+
+	/* write fixed quantitization tables */
+	adr = 0x0cc;
+	for (i = 0; i < sizeof(dqt); ++i) {
+		zr36060_write_8(zr, adr++, dqt[i]);
+	}
+}
+
+static void zr36060_set_jpg_DHT(struct zoran *zr)
+{
+	unsigned i;
+	unsigned adr;
+	static const u8 dht[] =
+	{
+		0xff, 0xc4,	/* DHT marker */
+		0x01, 0xa2,	/* DHT length */
+		0x00,		/* table class 0, ID 0 */
+		0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,		/* # codes of length 1..8 */
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,		/* # codes of length 8..16 */
+		0x00,		/* values for codes of length 2 */
+		0x01, 0x02, 0x03, 0x04, 0x05,	/* values for codes of length 3 */
+		0x06,		/* values for codes of length 4 */
+		0x07,		/* values for codes of length 5 */
+		0x08,		/* values for codes of length 6 */
+		0x09,		/* values for codes of length 7 */
+		0x0a,		/* values for codes of length 8 */
+		0x0b,		/* values for codes of length 9 */
+		0x01,		/* table class 0, ID 1 */
+		0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,		/* # codes of length 1..8 */
+		0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,		/* # codes of length 9..16 */
+		0x00, 0x01, 0x02,	/* values for codes of length 2 */
+		0x03,		/* values for codes of length 3 */
+		0x04,		/* values for codes of length 4 */
+		0x05,		/* values for codes of length 5 */
+		0x06,		/* values for codes of length 6 */
+		0x07,		/* values for codes of length 7 */
+		0x08,		/* values for codes of length 8 */
+		0x09,		/* values for codes of length 9 */
+		0x0a,		/* values for codes of length 10 */
+		0x0b,		/* values for codes of length 11 */
+		0x10,
+		0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+		0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+		0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+		0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+		0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+		0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+		0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+		0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+		0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+		0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+		0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+		0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+		0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+		0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+		0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+		0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+		0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+		0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+		0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+		0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+		0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+		0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+		0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+		0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
+		0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
+		0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+		0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,
+		0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23,
+		0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a,
+		0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
+		0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35,
+		0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+		0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55,
+		0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+		0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
+		0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84,
+		0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+		0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
+		0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+		0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+		0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+		0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+		0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+	};
+
+	/* write fixed Huffman tables */
+	adr = 0x1d4;
+	for (i = 0; i < sizeof(dht); ++i) {
+		zr36060_write_8(zr, adr++, dht[i]);
+	}
+}
+
+static void zr36060_set_jpg_APP(struct zoran *zr)
+{
+	unsigned adr;
+	int len, i;
+	u32 reg;
+
+
+	len = zr->params.APP_len;
+	if (len < 0)
+		len = 0;
+	if (len > 60)
+		len = 60;
+
+	i = zr->params.APPn;
+	if (i < 0)
+		i = 0;
+	if (i > 15)
+		i = 15;
+
+	reg = 0xffe0 + i;	/* APPn marker */
+	zr36060_write_16(zr, 0x380, reg);
+
+	reg = len + 2;		/* APPn len */
+	zr36060_write_16(zr, 0x382, reg);
+
+	/* write APPn data */
+	adr = 0x384;
+	for (i = 0; i < 60; i++) {
+		zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0));
+	}
+}
+
+static void zr36060_set_jpg_COM(struct zoran *zr)
+{
+	unsigned adr;
+	int len, i;
+	u32 reg;
+
+
+	len = zr->params.COM_len;
+	if (len < 0)
+		len = 0;
+	if (len > 60)
+		len = 60;
+
+	reg = 0xfffe;		/* COM marker */
+	zr36060_write_16(zr, 0x3c0, reg);
+
+	reg = len + 2;		/* COM len */
+	zr36060_write_16(zr, 0x3c2, reg);
+
+	/* write COM data */
+	adr = 0x3c4;
+	for (i = 0; i < 60; i++) {
+		zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0));
+	}
+}
+
+static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	unsigned i;
+	u32 reg;
+
+	zr36060_reset(zr);
+	mdelay(10);
+
+	reg = (0 << 7)		/* Load=0 */
+	    |(1 << 0);		/* SynRst=1 */
+	zr36060_write_8(zr, 0x000, reg);
+
+	zr36060_set_jpg(zr, mode);
+	zr36060_set_video(zr, mode);
+	zr36060_set_jpg_SOF(zr);
+	zr36060_set_jpg_SOS(zr);
+	zr36060_set_jpg_DRI(zr);
+	zr36060_set_jpg_DQT(zr);
+	zr36060_set_jpg_DHT(zr);
+	zr36060_set_jpg_APP(zr);
+	zr36060_set_jpg_COM(zr);
+
+	reg = (1 << 7)		/* Load=1 */
+	    |(0 << 0);		/* SynRst=0 */
+	zr36060_write_8(zr, 0x000, reg);
+
+	/* wait for codec to unbusy */
+	for (i = 0; i < 1000; ++i) {
+		reg = zr36060_read_8(zr, 0x001);
+		if ((reg & (1 << 7)) == 0) {
+			DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i));
+			return;
+		}
+		udelay(1000);
+	}
+	printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg);
+}
+
+static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+	int i;
+
+	tvn = &tvnorms[zr->params.norm];
+
+	/* assert P_Reset */
+	btwrite(0, ZR36057_JPC);
+
+	/* re-initialize DMA ring stuff */
+	zr->jpg_que_head = 0;
+	zr->jpg_dma_head = 0;
+	zr->jpg_dma_tail = 0;
+	zr->jpg_que_tail = 0;
+	zr->jpg_seq_num = 0;
+	for (i = 0; i < BUZ_NUM_STAT_COM; ++i) {
+		zr->stat_com[i] = 1;	/* mark as unavailable to zr36057 */
+	}
+	for (i = 0; i < zr->jpg_nbufs; i++) {
+		zr->jpg_gbuf[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+
+	/* MJPEG compression mode */
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS:
+	default:
+		reg = ZR36057_JMC_MJPGCmpMode;
+		break;
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = ZR36057_JMC_MJPGExpMode;
+		reg |= ZR36057_JMC_SyncMstr;
+		/* RJ: The following is experimental - improves the output to screen */
+		if (zr->params.VFIFO_FB)
+			reg |= ZR36057_JMC_VFIFO_FB;
+		break;
+
+	case BUZ_MODE_STILL_COMPRESS:
+		reg = ZR36057_JMC_JPGCmpMode;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+		reg = ZR36057_JMC_JPGExpMode;
+		break;
+
+	}
+	reg |= ZR36057_JMC_JPG;
+	if (zr->params.field_per_buff == 1)
+		reg |= ZR36057_JMC_Fld_per_buff;
+	btwrite(reg, ZR36057_JMC);
+
+	/* vertical */
+	btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
+	reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot);
+	btwrite(reg, ZR36057_VSP);
+	reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY)
+	    | (zr->params.img_height << ZR36057_FVAP_PAY);
+	btwrite(reg, ZR36057_FVAP);
+
+	/* horizontal */
+	btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+	reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot);
+	btwrite(reg, ZR36057_HSP);
+	reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX)
+	    | (zr->params.img_width << ZR36057_FHAP_PAX);
+	btwrite(reg, ZR36057_FHAP);
+
+	/* field process parameters */
+	if (zr->params.odd_even)
+		reg = ZR36057_FPP_Odd_Even;
+	else
+		reg = 0;
+	btwrite(reg, ZR36057_FPP);
+
+	/* Set proper VCLK Polarity, else colors will be wrong during playback */
+	btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
+
+	/* code base address and FIFO threshold */
+	reg = virt_to_bus(zr->stat_com);
+	btwrite(reg, ZR36057_JCBA);
+	reg = 0x50;
+	btwrite(reg, ZR36057_JCFT);
+
+	/* JPEG codec guest ID */
+	reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg);
+	btwrite(reg, ZR36057_JCGI);
+
+	/* Code transfer guest ID */
+	reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg);
+	reg |= ZR36057_MCTCR_CFlush;
+	btwrite(reg, ZR36057_MCTCR);
+
+	/* deassert P_Reset */
+	btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+}
+
+static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	static int zero = 0;
+	static int one = 1;
+
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS:
+		zr36060_set_cap(zr, mode);
+		zr36057_set_jpg(zr, mode);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero);
+
+		/* deassert P_Reset, assert Code transfer enable */
+		btwrite(IRQ_MASK, ZR36057_ISR);
+		btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+		break;
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one);
+		zr36060_set_cap(zr, mode);
+		zr36057_set_jpg(zr, mode);
+
+		/* deassert P_Reset, assert Code transfer enable */
+		btwrite(IRQ_MASK, ZR36057_ISR);
+		btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+		break;
+
+	case BUZ_MODE_IDLE:
+	default:
+		/* shut down processing */
+		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+		btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
+		btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
+		btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+		btwrite(0, ZR36057_ISR);
+		zr36060_reset(zr);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero);
+		break;
+
+	}
+	zr->codec_mode = mode;
+}
+
+/*
+ *   Queue a MJPEG buffer for capture/playback
+ */
+
+static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode)
+{
+	unsigned long flags;
+	int res;
+
+	/* Check if buffers are allocated */
+
+	if (!zr->jpg_buffers_allocated) {
+		printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name);
+		return -ENOMEM;
+	}
+	/* Does the user want to stop streaming? */
+
+	if (frame < 0) {
+		if (zr->codec_mode == mode) {
+			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+			return 0;
+		} else {
+			printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name);
+			return -EINVAL;
+		}
+	}
+	/* No grabbing outside the buffer range! */
+
+	if (frame >= zr->jpg_nbufs) {
+		printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame);
+		return -EINVAL;
+	}
+	/* what is the codec mode right now? */
+
+	if (zr->codec_mode == BUZ_MODE_IDLE) {
+		/* Ok load up the zr36060 and go */
+		zr36057_enable_jpg(zr, mode);
+	} else if (zr->codec_mode != mode) {
+		/* wrong codec mode active - invalid */
+		printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name);
+		return -EINVAL;
+	}
+	spin_lock_irqsave(&zr->lock, flags);
+
+	/* make sure a grab isn't going on currently with this buffer */
+
+	switch (zr->jpg_gbuf[frame].state) {
+
+	default:
+	case BUZ_STATE_DMA:
+	case BUZ_STATE_PEND:
+	case BUZ_STATE_DONE:
+		res = -EBUSY;	/* what are you doing? */
+		break;
+
+	case BUZ_STATE_USER:
+		/* since there is at least one unused buffer there's room for at least one more pend[] entry */
+		zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame;
+		zr->jpg_gbuf[frame].state = BUZ_STATE_PEND;
+		zoran_feed_stat_com(zr);
+		res = 0;
+		break;
+
+	}
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	/* Start the zr36060 when the first frame is queued  */
+	if (zr->jpg_que_head == 1) {
+		btor(ZR36057_JMC_Go_en, ZR36057_JMC);
+		btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC);
+	}
+	return res;
+}
+
+/*
+ *   Sync on a MJPEG buffer
+ */
+
+static int jpg_sync(struct zoran *zr, struct zoran_sync *bs)
+{
+	unsigned long flags;
+	int frame;
+
+	if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
+	    zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
+		return -EINVAL;
+	}
+	while (zr->jpg_que_tail == zr->jpg_dma_tail) {
+		interruptible_sleep_on(&zr->jpg_capq);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
+
+	/* buffer should now be in BUZ_STATE_DONE */
+
+	if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE)
+		printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name);
+
+	*bs = zr->jpg_gbuf[frame].bs;
+	zr->jpg_gbuf[frame].state = BUZ_STATE_USER;
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return 0;
+}
+
+/* when this is called the spinlock must be held */
+static void zoran_feed_stat_com(struct zoran *zr)
+{
+	/* move frames from pending queue to DMA */
+
+	int frame, i, max_stat_com;
+
+	max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
+
+	while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com
+	       && zr->jpg_dma_head != zr->jpg_que_head) {
+
+		frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
+		if (zr->params.TmpDcm == 1) {
+			/* fill 1 stat_com entry */
+			i = zr->jpg_dma_head & BUZ_MASK_STAT_COM;
+			zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
+		} else {
+			/* fill 2 stat_com entries */
+			i = (zr->jpg_dma_head & 1) * 2;
+			zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
+			zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus;
+		}
+		zr->jpg_gbuf[frame].state = BUZ_STATE_DMA;
+		zr->jpg_dma_head++;
+
+	}
+}
+
+/* when this is called the spinlock must be held */
+static void zoran_reap_stat_com(struct zoran *zr)
+{
+	/* move frames from DMA queue to done queue */
+
+	int i;
+	u32 stat_com;
+	unsigned int seq;
+	unsigned int dif;
+	int frame;
+	struct zoran_gbuffer *gbuf;
+
+	/* In motion decompress we don't have a hardware frame counter,
+	   we just count the interrupts here */
+
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+		zr->jpg_seq_num++;
+
+	while (zr->jpg_dma_tail != zr->jpg_dma_head) {
+		if (zr->params.TmpDcm == 1)
+			i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM;
+		else
+			i = (zr->jpg_dma_tail & 1) * 2 + 1;
+
+		stat_com = zr->stat_com[i];
+
+		if ((stat_com & 1) == 0) {
+			return;
+		}
+		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+		gbuf = &zr->jpg_gbuf[frame];
+		get_fast_time(&gbuf->bs.timestamp);
+
+		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+			gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
+
+			/* update sequence number with the help of the counter in stat_com */
+
+			seq = stat_com >> 24;
+			dif = (seq - zr->jpg_seq_num) & 0xff;
+			zr->jpg_seq_num += dif;
+		} else {
+			gbuf->bs.length = 0;
+		}
+		gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
+		gbuf->state = BUZ_STATE_DONE;
+
+		zr->jpg_dma_tail++;
+	}
+}
+
+static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 stat, astat;
+	int count;
+	struct zoran *zr;
+	unsigned long flags;
+
+	zr = (struct zoran *) dev_id;
+	count = 0;
+
+	spin_lock_irqsave(&zr->lock, flags);
+	while (1) {
+		/* get/clear interrupt status bits */
+		stat = btread(ZR36057_ISR);
+		astat = stat & IRQ_MASK;
+		if (!astat) {
+			break;
+		}
+		btwrite(astat, ZR36057_ISR);
+		IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat));
+
+#if (IRQ_MASK & ZR36057_ISR_GIRQ0)
+		if (astat & ZR36057_ISR_GIRQ0) {
+
+			/* Interrupts may still happen when zr->v4l_memgrab_active is switched off.
+			   We simply ignore them */
+
+			if (zr->v4l_memgrab_active) {
+
+/* A lot more checks should be here ... */
+				if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0)
+					printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name);
+
+				if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
+					/* There is a grab on a frame going on, check if it has finished */
+
+					if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) {
+						/* it is finished, notify the user */
+
+						zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
+						zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+						zr->v4l_grab_seq++;
+						zr->v4l_pend_tail++;
+					}
+				}
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
+					wake_up_interruptible(&zr->v4l_capq);
+
+				/* Check if there is another grab queued */
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
+				    zr->v4l_pend_tail != zr->v4l_pend_head) {
+
+					int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
+					u32 reg;
+
+					zr->v4l_grab_frame = frame;
+
+					/* Set zr36057 video front end and enable video */
+
+					/* Buffer address */
+
+					reg = zr->v4l_gbuf[frame].fbuffer_bus;
+					btwrite(reg, ZR36057_VDTR);
+					if (zr->video_interlace)
+						reg += zr->gbpl;
+					btwrite(reg, ZR36057_VDBR);
+
+					/* video stride, status, and frame grab register */
+
+#ifdef XAWTV_HACK
+					reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0;
+#else
+					reg = 0;
+#endif
+					if (zr->video_interlace)
+						reg += zr->gbpl;
+					reg = (reg << ZR36057_VSSFGR_DispStride);
+					reg |= ZR36057_VSSFGR_VidOvf;
+					reg |= ZR36057_VSSFGR_SnapShot;
+					reg |= ZR36057_VSSFGR_FrameGrab;
+					btwrite(reg, ZR36057_VSSFGR);
+
+					btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+				}
+			}
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_GIRQ0) */
+
+#if (IRQ_MASK & ZR36057_ISR_GIRQ1)
+		if (astat & ZR36057_ISR_GIRQ1) {
+			unsigned csr = zr36060_read_8(zr, 0x001);
+			unsigned isr = zr36060_read_8(zr, 0x008);
+
+			IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n",
+				      zr->name, csr, isr));
+
+			btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR);
+			zoran_reap_stat_com(zr);
+			zoran_feed_stat_com(zr);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_GIRQ1) */
+
+#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+		if (astat & ZR36057_ISR_CodRepIRQ) {
+			IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name));
+			btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
+
+#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
+		if ((astat & ZR36057_ISR_JPEGRepIRQ) &&
+		    (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
+		     zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
+			zoran_reap_stat_com(zr);
+			zoran_feed_stat_com(zr);
+			wake_up_interruptible(&zr->jpg_capq);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+		count++;
+		if (count > 10) {
+			printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count);
+			if (count > 20) {
+				btwrite(0, ZR36057_ICR);
+				printk(KERN_ERR  "%s: IRQ lockup, cleared int mask\n", zr->name);
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&zr->lock, flags);
+}
+
+/* Check a zoran_params struct for correctness, insert default params */
+
+static int zoran_check_params(struct zoran *zr, struct zoran_params *params)
+{
+	int err = 0, err0 = 0;
+
+	/* insert constant params */
+
+	params->major_version = MAJOR_VERSION;
+	params->minor_version = MINOR_VERSION;
+
+	/* Check input and norm */
+
+	if (params->input != 0 && params->input != 1) {
+		err++;
+	}
+	if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) {
+		err++;
+	}
+	/* Check decimation, set default values for decimation = 1, 2, 4 */
+
+	switch (params->decimation) {
+	case 1:
+
+		params->HorDcm = 1;
+		params->VerDcm = 1;
+		params->TmpDcm = 1;
+		params->field_per_buff = 2;
+
+		params->img_x = 0;
+		params->img_y = 0;
+		params->img_width = 720;
+		params->img_height = tvnorms[params->norm].Ha / 2;
+		break;
+
+	case 2:
+
+		params->HorDcm = 2;
+		params->VerDcm = 1;
+		params->TmpDcm = 2;
+		params->field_per_buff = 1;
+
+		params->img_x = 8;
+		params->img_y = 0;
+		params->img_width = 704;
+		params->img_height = tvnorms[params->norm].Ha / 2;
+		break;
+
+	case 4:
+
+		params->HorDcm = 4;
+		params->VerDcm = 2;
+		params->TmpDcm = 2;
+		params->field_per_buff = 1;
+
+		params->img_x = 8;
+		params->img_y = 0;
+		params->img_width = 704;
+		params->img_height = tvnorms[params->norm].Ha / 2;
+		break;
+
+	case 0:
+
+		/* We have to check the data the user has set */
+
+		if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4)
+			err0++;
+		if (params->VerDcm != 1 && params->VerDcm != 2)
+			err0++;
+		if (params->TmpDcm != 1 && params->TmpDcm != 2)
+			err0++;
+		if (params->field_per_buff != 1 && params->field_per_buff != 2)
+			err0++;
+
+		if (params->img_x < 0)
+			err0++;
+		if (params->img_y < 0)
+			err0++;
+		if (params->img_width < 0)
+			err0++;
+		if (params->img_height < 0)
+			err0++;
+		if (params->img_x + params->img_width > 720)
+			err0++;
+		if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2)
+			err0++;
+		if (params->img_width % (16 * params->HorDcm) != 0)
+			err0++;
+		if (params->img_height % (8 * params->VerDcm) != 0)
+			err0++;
+
+		if (err0) {
+			err++;
+		}
+		break;
+
+	default:
+		err++;
+		break;
+	}
+
+	if (params->quality > 100)
+		params->quality = 100;
+	if (params->quality < 5)
+		params->quality = 5;
+
+	if (params->APPn < 0)
+		params->APPn = 0;
+	if (params->APPn > 15)
+		params->APPn = 15;
+	if (params->APP_len < 0)
+		params->APP_len = 0;
+	if (params->APP_len > 60)
+		params->APP_len = 60;
+	if (params->COM_len < 0)
+		params->COM_len = 0;
+	if (params->COM_len > 60)
+		params->COM_len = 60;
+
+	if (err)
+		return -EINVAL;
+
+	return 0;
+
+}
+static void zoran_open_init_params(struct zoran *zr)
+{
+	int i;
+
+	/* Per default, map the V4L Buffers */
+
+	zr->map_mjpeg_buffers = 0;
+
+	/* User must explicitly set a window */
+
+	zr->window_set = 0;
+
+	zr->window.x = 0;
+	zr->window.y = 0;
+	zr->window.width = 0;
+	zr->window.height = 0;
+	zr->window.chromakey = 0;
+	zr->window.flags = 0;
+	zr->window.clips = NULL;
+	zr->window.clipcount = 0;
+
+	zr->video_interlace = 0;
+
+	zr->v4l_memgrab_active = 0;
+	zr->v4l_overlay_active = 0;
+
+	zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+	zr->v4l_grab_seq = 0;
+
+	zr->gwidth = 0;
+	zr->gheight = 0;
+	zr->gformat = 0;
+	zr->gbpl = 0;
+
+	/* DMA ring stuff for V4L */
+
+	zr->v4l_pend_tail = 0;
+	zr->v4l_pend_head = 0;
+	for (i = 0; i < v4l_nbufs; i++) {
+		zr->v4l_gbuf[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+
+	/* Set necessary params and call zoran_check_params to set the defaults */
+
+	zr->params.decimation = 1;
+
+	zr->params.quality = 50;	/* default compression factor 8 */
+	zr->params.odd_even = 1;
+
+	zr->params.APPn = 0;
+	zr->params.APP_len = 0;	/* No APPn marker */
+	for (i = 0; i < 60; i++)
+		zr->params.APP_data[i] = 0;
+
+	zr->params.COM_len = 0;	/* No COM marker */
+	for (i = 0; i < 60; i++)
+		zr->params.COM_data[i] = 0;
+
+	zr->params.VFIFO_FB = 0;
+
+	memset(zr->params.reserved, 0, sizeof(zr->params.reserved));
+
+	zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+
+	i = zoran_check_params(zr, &zr->params);
+	if (i)
+		printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name);
+}
+
+/*
+ *   Open a buz card. Right now the flags stuff is just playing
+ */
+
+static int zoran_open(struct video_device *dev, int flags)
+{
+	struct zoran *zr = (struct zoran *) dev;
+
+	DEBUG(printk(KERN_INFO ": zoran_open\n"));
+
+	switch (flags) {
+
+	case 0:
+		if (zr->user)
+			return -EBUSY;
+		zr->user++;
+
+		if (v4l_fbuffer_alloc(zr) < 0) {
+			zr->user--;
+			return -ENOMEM;
+		}
+		/* default setup */
+
+		zoran_open_init_params(zr);
+
+		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+
+		btwrite(IRQ_MASK, ZR36057_ISR);		// Clears interrupts
+
+		btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+		break;
+
+	default:
+		return -EBUSY;
+
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void zoran_close(struct video_device *dev)
+{
+	struct zoran *zr = (struct zoran *) dev;
+
+	DEBUG(printk(KERN_INFO ": zoran_close\n"));
+	
+	/* disable interrupts */
+	btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+	/* wake up sleeping beauties */
+	wake_up_interruptible(&zr->v4l_capq);
+	wake_up_interruptible(&zr->jpg_capq);
+
+	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+	zr36057_set_memgrab(zr, 0);
+	if (zr->v4l_overlay_active)
+		zr36057_overlay(zr, 0);
+
+	zr->user--;
+
+	v4l_fbuffer_free(zr);
+	jpg_fbuffer_free(zr);
+	zr->jpg_nbufs = 0;
+
+	MOD_DEC_USE_COUNT;
+	DEBUG(printk(KERN_INFO ": zoran_close done\n"));
+}
+
+
+static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock)
+{
+	return -EINVAL;
+}
+
+static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock)
+{
+	return -EINVAL;
+}
+
+/*
+ *   ioctl routine
+ */
+
+
+static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct zoran *zr = (struct zoran *) dev;
+
+	switch (cmd) {
+
+	case VIDIOCGCAP:
+		{
+			struct video_capability b;
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n"));
+			strncpy(b.name, zr->video_dev.name, sizeof(b.name));
+			b.type = VID_TYPE_CAPTURE |
+			    VID_TYPE_OVERLAY |
+			    VID_TYPE_CLIPPING |
+			    VID_TYPE_FRAMERAM |
+			    VID_TYPE_SCALES;
+			/* theoretically we could also flag VID_TYPE_SUBCAPTURE
+			   but this is not even implemented in the BTTV driver */
+
+			b.channels = 2;		/* composite, svhs */
+			b.audios = 0;
+			b.maxwidth = BUZ_MAX_WIDTH;
+			b.maxheight = BUZ_MAX_HEIGHT;
+			b.minwidth = BUZ_MIN_WIDTH;
+			b.minheight = BUZ_MIN_HEIGHT;
+			if (copy_to_user(arg, &b, sizeof(b))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case VIDIOCGCHAN:
+		{
+			struct video_channel v;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel));
+			switch (v.channel) {
+			case 0:
+				strcpy(v.name, "Composite");
+				break;
+			case 1:
+				strcpy(v.name, "SVHS");
+				break;
+			default:
+				return -EINVAL;
+			}
+			v.tuners = 0;
+			v.flags = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = zr->params.norm;
+			if (copy_to_user(arg, &v, sizeof(v))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+		/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
+
+		 * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
+		 *                                 ^^^^^^^
+		 * The famos BTTV driver has it implemented with a struct video_channel argument
+		 * and we follow it for compatibility reasons
+		 *
+		 * BTW: this is the only way the user can set the norm!
+		 */
+
+	case VIDIOCSCHAN:
+		{
+			struct video_channel v;
+			int input;
+			int on, res;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm));
+			switch (v.channel) {
+			case 0:
+				input = 3;
+				break;
+			case 1:
+				input = 7;
+				break;
+			default:
+				return -EINVAL;
+			}
+
+			if (v.norm != VIDEO_MODE_PAL
+			    && v.norm != VIDEO_MODE_NTSC) {
+				return -EINVAL;
+			}
+			zr->params.norm = v.norm;
+			zr->params.input = v.channel;
+
+			/* We switch overlay off and on since a change in the norm
+			   needs different VFE settings */
+
+			on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
+			if (on)
+				zr36057_overlay(zr, 0);
+
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+
+			if (on)
+				zr36057_overlay(zr, 1);
+
+			/* Make sure the changes come into effect */
+			res = wait_grab_pending(zr);
+			if (res)
+				return res;
+
+			return 0;
+		}
+
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+			return -EINVAL;
+
+	case VIDIOCGPICT:
+		{
+			struct video_picture p = zr->picture;
+
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n"));
+			p.depth = zr->buffer.depth;
+			switch (zr->buffer.depth) {
+			case 15:
+				p.palette = VIDEO_PALETTE_RGB555;
+				break;
+
+			case 16:
+				p.palette = VIDEO_PALETTE_RGB565;
+				break;
+
+			case 24:
+				p.palette = VIDEO_PALETTE_RGB24;
+				break;
+
+			case 32:
+				p.palette = VIDEO_PALETTE_RGB32;
+				break;
+			}
+
+			if (copy_to_user(arg, &p, sizeof(p))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case VIDIOCSPICT:
+		{
+			struct video_picture p;
+
+			if (copy_from_user(&p, arg, sizeof(p))) {
+				return -EFAULT;
+			}
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n",
+					   p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette));
+			/* The depth and palette values have no meaning to us,
+			   should we return  -EINVAL if they don't fit ? */
+			zr->picture = p;
+			return 0;
+		}
+
+	case VIDIOCCAPTURE:
+		{
+			int v, res;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v));
+			/* If there is nothing to do, return immediatly */
+
+			if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active))
+				return 0;
+
+			if (v == 0) {
+				zr->v4l_overlay_active = 0;
+				if (!zr->v4l_memgrab_active)
+					zr36057_overlay(zr, 0);
+				/* When a grab is running, the video simply won't be switched on any more */
+			} else {
+				if (!zr->buffer_set || !zr->window_set) {
+					return -EINVAL;
+				}
+				zr->v4l_overlay_active = 1;
+				if (!zr->v4l_memgrab_active)
+					zr36057_overlay(zr, 1);
+				/* When a grab is running, the video will be switched on when grab is finished */
+			}
+			/* Make sure the changes come into effect */
+			res = wait_grab_pending(zr);
+			if (res)
+				return res;
+			return 0;
+		}
+
+	case VIDIOCGWIN:
+		{
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n"));
+			if (copy_to_user(arg, &zr->window, sizeof(zr->window))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case VIDIOCSWIN:
+		{
+			struct video_clip *vcp;
+			struct video_window vw;
+			int on, end, res;
+
+			if (copy_from_user(&vw, arg, sizeof(vw))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount));
+			if (!zr->buffer_set) {
+				return -EINVAL;
+			}
+			/*
+			 * The video front end needs 4-byte alinged line sizes, we correct that
+			 * silently here if necessary
+			 */
+
+			if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
+				end = (vw.x + vw.width) & ~1;	/* round down */
+				vw.x = (vw.x + 1) & ~1;		/* round up */
+				vw.width = end - vw.x;
+			}
+			if (zr->buffer.depth == 24) {
+				end = (vw.x + vw.width) & ~3;	/* round down */
+				vw.x = (vw.x + 3) & ~3;		/* round up */
+				vw.width = end - vw.x;
+			}
+#if 0
+			// At least xawtv seems to care about the following - just leave it away
+			/*
+			 * Also corrected silently (as long as window fits at all):
+			 * video not fitting the screen
+			 */
+#if 0
+			if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width ||
+			    vw.y + vw.height > zr->buffer.height) {
+				printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n",
+				       vw.width, vw.height, vw.x, vw.y);
+				return -EINVAL;
+			}
+#else
+			if (vw.x < 0)
+				vw.x = 0;
+			if (vw.y < 0)
+				vw.y = 0;
+			if (vw.x + vw.width > zr->buffer.width)
+				vw.width = zr->buffer.width - vw.x;
+			if (vw.y + vw.height > zr->buffer.height)
+				vw.height = zr->buffer.height - vw.y;
+#endif
+#endif
+
+			/* Check for vaild parameters */
+			if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT ||
+			    vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) {
+				return -EINVAL;
+			}
+#ifdef XAWTV_HACK
+			if (vw.width > 720)
+				vw.width = 720;
+#endif
+
+			zr->window.x = vw.x;
+			zr->window.y = vw.y;
+			zr->window.width = vw.width;
+			zr->window.height = vw.height;
+			zr->window.chromakey = 0;
+			zr->window.flags = 0;	// RJ: Is this intended for interlace on/off ?
+
+			zr->window.clips = NULL;
+			zr->window.clipcount = vw.clipcount;
+
+			/*
+			 * If an overlay is running, we have to switch it off
+			 * and switch it on again in order to get the new settings in effect.
+			 *
+			 * We also want to avoid that the overlay mask is written
+			 * when an overlay is running.
+			 */
+
+			on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
+			if (on)
+				zr36057_overlay(zr, 0);
+
+			/*
+			 *   Write the overlay mask if clips are wanted.
+			 */
+			if (vw.clipcount) {
+				vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4));
+				if (vcp == NULL) {
+					return -ENOMEM;
+				}
+				if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) {
+					vfree(vcp);
+					return -EFAULT;
+				}
+				write_overlay_mask(zr, vcp, vw.clipcount);
+				vfree(vcp);
+			}
+			if (on)
+				zr36057_overlay(zr, 1);
+			zr->window_set = 1;
+
+			/* Make sure the changes come into effect */
+			res = wait_grab_pending(zr);
+			if (res)
+				return res;
+
+			return 0;
+		}
+
+	case VIDIOCGFBUF:
+		{
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n"));
+			if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case VIDIOCSFBUF:
+		{
+			struct video_buffer v;
+
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline));
+			if (zr->v4l_overlay_active) {
+				/* Has the user gotten crazy ... ? */
+				return -EINVAL;
+			}
+			if (v.depth != 15
+			    && v.depth != 16
+			    && v.depth != 24
+			    && v.depth != 32) {
+				return -EINVAL;
+			}
+			if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) {
+				return -EINVAL;
+			}
+			if (v.bytesperline & 3) {
+				return -EINVAL;
+			}
+			if (v.base) {
+				zr->buffer.base = (void *) ((unsigned long) v.base & ~3);
+			}
+			zr->buffer.height = v.height;
+			zr->buffer.width = v.width;
+			zr->buffer.depth = v.depth;
+			zr->buffer.bytesperline = v.bytesperline;
+
+			if (zr->buffer.base)
+				zr->buffer_set = 1;
+			zr->window_set = 0;	/* The user should set new window parameters */
+			return 0;
+		}
+
+		/* RJ: what is VIDIOCKEY intended to do ??? */
+
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+		
+	case VIDIOCSYNC:
+		{
+			int v;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v));
+			return v4l_sync(zr, v);
+		}
+
+	case VIDIOCMCAPTURE:
+		{
+			struct video_mmap vm;
+
+			if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n",
+			       vm.frame, vm.height, vm.width, vm.format));
+			return v4l_grab(zr, &vm);
+		}
+
+	case VIDIOCGMBUF:
+		{
+			struct video_mbuf vm;
+			int i;
+
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n"));
+		
+			vm.size = v4l_nbufs * v4l_bufsize;
+			vm.frames = v4l_nbufs;
+			for (i = 0; i < v4l_nbufs; i++) {
+				vm.offsets[i] = i * v4l_bufsize;
+			}
+
+			/* The next mmap will map the V4L buffers */
+			zr->map_mjpeg_buffers = 0;
+
+			if (copy_to_user(arg, &vm, sizeof(vm))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case VIDIOCGUNIT:
+		{
+			struct video_unit vu;
+
+			IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n"));
+			vu.video = zr->video_dev.minor;
+			vu.vbi = VIDEO_NO_UNIT;
+			vu.radio = VIDEO_NO_UNIT;
+			vu.audio = VIDEO_NO_UNIT;
+			vu.teletext = VIDEO_NO_UNIT;
+			if (copy_to_user(arg, &vu, sizeof(vu)))
+				return -EFAULT;
+			return 0;
+		}
+
+		/*
+		 * RJ: In principal we could support subcaptures for V4L grabbing.
+		 *     Not even the famous BTTV driver has them, however.
+		 *     If there should be a strong demand, one could consider
+		 *     to implement them.
+		 */
+	case VIDIOCGCAPTURE:
+	case VIDIOCSCAPTURE:
+			return -EINVAL;
+
+	case BUZIOC_G_PARAMS:
+		{
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n"));
+			if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) 
+				return -EFAULT;
+			return 0;
+		}
+
+	case BUZIOC_S_PARAMS:
+		{
+			struct zoran_params bp;
+			int input, on;
+
+			if (zr->codec_mode != BUZ_MODE_IDLE) {
+				return -EINVAL;
+			}
+			if (copy_from_user(&bp, arg, sizeof(bp))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n"));
+			
+			/* Check the params first before overwriting our internal values */
+
+			if (zoran_check_params(zr, &bp))
+				return -EINVAL;
+
+			zr->params = bp;
+
+			/* Make changes of input and norm go into effect immediatly */
+
+			/* We switch overlay off and on since a change in the norm
+			   needs different VFE settings */
+
+			on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
+			if (on)
+				zr36057_overlay(zr, 0);
+
+			input = zr->params.input == 0 ? 3 : 7;
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+
+			if (on)
+				zr36057_overlay(zr, 1);
+
+			if (copy_to_user(arg, &bp, sizeof(bp))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case BUZIOC_REQBUFS:
+		{
+			struct zoran_requestbuffers br;
+
+			if (zr->jpg_buffers_allocated) {
+				return -EINVAL;
+			}
+			if (copy_from_user(&br, arg, sizeof(br))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n",
+					   br.count, br.size));
+			/* Enforce reasonable lower and upper limits */
+			if (br.count < 4)
+				br.count = 4;	/* Could be choosen smaller */
+			if (br.count > BUZ_MAX_FRAME)
+				br.count = BUZ_MAX_FRAME;
+			br.size = PAGE_ALIGN(br.size);
+			if (br.size < 8192)
+				br.size = 8192;		/* Arbitrary */
+			/* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
+			if (br.size > (512 * 1024))
+				br.size = (512 * 1024);		/* 512 K should be enough */
+			if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM)
+				br.size = MAX_KMALLOC_MEM;
+
+			zr->jpg_nbufs = br.count;
+			zr->jpg_bufsize = br.size;
+
+			if (jpg_fbuffer_alloc(zr))
+				return -ENOMEM;
+
+			/* The next mmap will map the MJPEG buffers */
+			zr->map_mjpeg_buffers = 1;
+
+			if (copy_to_user(arg, &br, sizeof(br))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	case BUZIOC_QBUF_CAPT:
+		{
+			int nb;
+
+			if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb));
+			return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS);
+		}
+
+	case BUZIOC_QBUF_PLAY:
+		{
+			int nb;
+
+			if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb));
+			return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS);
+		}
+
+	case BUZIOC_SYNC:
+		{
+			struct zoran_sync bs;
+			int res;
+
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n"));
+			res = jpg_sync(zr, &bs);
+			if (copy_to_user(arg, &bs, sizeof(bs))) {
+				return -EFAULT;
+			}
+			return res;
+		}
+
+	case BUZIOC_G_STATUS:
+		{
+			struct zoran_status bs;
+			int norm, input, status;
+
+			if (zr->codec_mode != BUZ_MODE_IDLE) {
+				return -EINVAL;
+			}
+			if (copy_from_user(&bs, arg, sizeof(bs))) {
+				return -EFAULT;
+			}
+			IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n"));
+			switch (bs.input) {
+			case 0:
+				input = 3;
+				break;
+			case 1:
+				input = 7;
+				break;
+			default:
+				return -EINVAL;
+			}
+
+			/* Set video norm to VIDEO_MODE_AUTO */
+
+			norm = VIDEO_MODE_AUTO;
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+
+			/* sleep 1 second */
+
+			schedule_timeout(HZ);
+			
+			/* Get status of video decoder */
+
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status);
+			bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0;
+			bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
+			bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0;
+
+			/* restore previous input and norm */
+			input = zr->params.input == 0 ? 3 : 7;
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+
+			if (copy_to_user(arg, &bs, sizeof(bs))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+
+	default:
+		    return -ENOIOCTLCMD;
+
+	}
+	return 0;
+}
+
+
+/*
+ *   This maps the buffers to user space.
+ *
+ *   Depending on the state of zr->map_mjpeg_buffers
+ *   the V4L or the MJPEG buffers are mapped
+ *
+ */
+
+static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct zoran *zr = (struct zoran *) dev;
+	unsigned long start = (unsigned long) adr;
+	unsigned long page, pos, todo, fraglen;
+	int i, j;
+
+	if (zr->map_mjpeg_buffers) {
+		/* Map the MJPEG buffers */
+
+		if (!zr->jpg_buffers_allocated) {
+			return -ENOMEM;
+		}
+		if (size > zr->jpg_nbufs * zr->jpg_bufsize) {
+			return -EINVAL;
+		}
+
+		for (i = 0; i < zr->jpg_nbufs; i++) {
+			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+				fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1;
+				todo = size;
+				if (todo > fraglen)
+					todo = fraglen;
+				pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j];
+				page = virt_to_phys(bus_to_virt(pos));	/* should just be pos on i386 */
+				if (remap_page_range(start, page, todo, PAGE_SHARED)) {
+					printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name);
+					return -EAGAIN;
+				}
+				size -= todo;
+				start += todo;
+				if (size == 0)
+					break;
+				if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1)
+					break;	/* was last fragment */
+			}
+			if (size == 0)
+				break;
+		}
+	} else {
+		/* Map the V4L buffers */
+
+		if (size > v4l_nbufs * v4l_bufsize) {
+			return -EINVAL;
+		}
+
+		for (i = 0; i < v4l_nbufs; i++) {
+			todo = size;
+			if (todo > v4l_bufsize)
+				todo = v4l_bufsize;
+			page = zr->v4l_gbuf[i].fbuffer_phys;
+			DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start));
+			if (remap_page_range(start, page, todo, PAGE_SHARED)) {
+				printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name);
+				return -EAGAIN;
+			}
+			size -= todo;
+			start += todo;
+			if (size == 0)
+				break;
+		}
+	}
+	return 0;
+}
+
+static int zoran_init_done(struct video_device *dev)
+{
+	return 0;
+}
+
+static struct video_device zoran_template =
+{
+	BUZ_NAME,
+	VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
+	VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
+	VID_HARDWARE_BT848,	/* Not true, but the buz is not yet in the list */
+	zoran_open,
+	zoran_close,
+	zoran_read,
+	zoran_write,
+	NULL,
+	zoran_ioctl,
+	zoran_mmap,
+	zoran_init_done,
+	NULL,
+	0,
+	0
+};
+
+static int zr36057_init(int i)
+{
+	struct zoran *zr = &zoran[i];
+	unsigned long mem;
+	unsigned mem_needed;
+	int j;
+	int rev;
+
+	/* reset zr36057 */
+	btwrite(0, ZR36057_SPGPPCR);
+	mdelay(10);
+
+	/* default setup of all parameters which will persist beetween opens */
+
+	zr->user = 0;
+	
+	init_waitqueue_head(&zr->v4l_capq);
+	init_waitqueue_head(&zr->jpg_capq);
+
+	zr->map_mjpeg_buffers = 0;	/* Map V4L buffers by default */
+
+	zr->jpg_nbufs = 0;
+	zr->jpg_bufsize = 0;
+	zr->jpg_buffers_allocated = 0;
+
+	zr->buffer_set = 0;	/* Flag if frame buffer has been set */
+	zr->buffer.base = (void *) vidmem;
+	zr->buffer.width = 0;
+	zr->buffer.height = 0;
+	zr->buffer.depth = 0;
+	zr->buffer.bytesperline = 0;
+
+	zr->params.norm = default_norm ? 1 : 0;	/* Avoid nonsense settings from user */
+	zr->params.input = default_input ? 1 : 0;	/* Avoid nonsense settings from user */
+	zr->video_interlace = 0;
+
+	/* Should the following be reset at every open ? */
+
+	zr->picture.colour = 32768;
+	zr->picture.brightness = 32768;
+	zr->picture.hue = 32768;
+	zr->picture.contrast = 32768;
+	zr->picture.whiteness = 0;
+	zr->picture.depth = 0;
+	zr->picture.palette = 0;
+
+	for (j = 0; j < VIDEO_MAX_FRAME; j++) {
+		zr->v4l_gbuf[i].fbuffer = 0;
+		zr->v4l_gbuf[i].fbuffer_phys = 0;
+		zr->v4l_gbuf[i].fbuffer_bus = 0;
+	}
+
+	zr->stat_com = 0;
+
+	/* default setup (will be repeated at every open) */
+
+	zoran_open_init_params(zr);
+
+	/* allocate memory *before* doing anything to the hardware in case allocation fails */
+
+	/* STAT_COM table and overlay mask */
+
+	mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4;
+	mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
+	if (!mem) {
+		return -ENOMEM;
+	}
+	memset((void *) mem, 0, mem_needed);
+
+	zr->stat_com = (u32 *) mem;
+	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+		zr->stat_com[j] = 1;	/* mark as unavailable to zr36057 */
+	}
+	zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4);
+
+	/* Initialize zr->jpg_gbuf */
+
+	for (j = 0; j < BUZ_MAX_FRAME; j++) {
+		zr->jpg_gbuf[j].frag_tab = 0;
+		zr->jpg_gbuf[j].frag_tab_bus = 0;
+		zr->jpg_gbuf[j].state = BUZ_STATE_USER;
+		zr->jpg_gbuf[j].bs.frame = j;
+	}
+
+	/* take zr36057 out of reset now */
+	btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
+	mdelay(10);
+
+	/* stop all DMA processes */
+	btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+	btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	/* assert P_Reset */
+	btwrite(0, ZR36057_JPC);
+
+	switch(zr->board)
+	{
+		case BOARD_BUZ:
+	
+			/* set up GPIO direction */
+			btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
+
+			/* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */
+			btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1);
+			mdelay(10);
+
+			/* reset video decoder */
+
+			GPIO(zr, 0, 0);
+			mdelay(10);
+			GPIO(zr, 0, 1);
+			mdelay(10);
+
+			/* reset JPEG codec */
+			zr36060_sleep(zr, 0);
+			mdelay(10);
+			zr36060_reset(zr);
+			mdelay(10);
+			zr36060_sleep(zr, 1);
+			mdelay(10);
+	
+			/* display codec revision */
+			if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
+				printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
+			       zr->name, zr36060_read_8(zr, 0x023));
+			} else {
+				printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev);
+				kfree((void *) zr->stat_com);
+				return -1;
+			}
+			break;
+			
+		case BOARD_LML33:
+//			btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR);
+//			udelay(100);
+//			btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR);
+//			udelay(1000);
+
+			/*
+			 *	Set up the GPIO direction
+			 */
+			btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR);
+			/* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */
+			btwrite(0xFF00F888, ZR36057_GPPGCR1);
+			mdelay(10);
+			GPIO(zr, 5, 0);		/* Analog video bypass */
+			udelay(3000);
+			GPIO(zr, 0, 0); 	/* Reset 819 */
+			udelay(3000);
+			GPIO(zr, 0, 1);		/* 819 back */
+			udelay(3000);
+			/* reset JPEG codec */
+			zr36060_sleep(zr, 0);
+			udelay(3000);
+			zr36060_reset(zr);
+			udelay(3000);
+			zr36060_sleep(zr, 1);
+			udelay(3000);
+
+			/* display codec revision */
+			if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
+				printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
+			       zr->name, zr36060_read_8(zr, 0x023));
+			} else {
+				printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev);
+//				kfree((void *) zr->stat_com);
+//				return -1;
+			}
+			break;
+	}
+	/* i2c */
+	memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus));
+	sprintf(zr->i2c.name, "zoran%u%u", zr->id);
+	zr->i2c.data = zr;
+	if (i2c_register_bus(&zr->i2c) < 0) {
+		kfree((void *) zr->stat_com);
+		return -1;
+	}
+	/*
+	 *   Now add the template and register the device unit.
+	 */
+	memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
+	sprintf(zr->video_dev.name, "zoran%u", zr->id);
+	if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) {
+		i2c_unregister_bus(&zr->i2c);
+		kfree((void *) zr->stat_com);
+		return -1;
+	}
+	/* toggle JPEG codec sleep to sync PLL */
+	zr36060_sleep(zr, 1);
+	mdelay(10);
+	zr36060_sleep(zr, 0);
+	mdelay(10);
+
+	/* Enable bus-mastering */
+	pci_set_master(zr->pci_dev);
+
+	j = zr->params.input == 0 ? 3 : 7;
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j);
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+
+	/* set individual interrupt enables (without GIRQ0)
+	   but don't global enable until zoran_open() */
+
+	btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR);
+
+	if(request_irq(zr->pci_dev->irq, zoran_irq,
+	       SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0)
+	{
+		printk(KERN_ERR "%s: Can't assign irq.\n", zr->name);
+		video_unregister_device(&zr->video_dev);
+		i2c_unregister_bus(&zr->i2c);
+		kfree((void *) zr->stat_com);
+		return -1;
+	}
+	zr->initialized = 1;
+	return 0;
+}
+
+
+
+static void release_zoran(void)
+{
+	u8 command;
+	int i;
+	struct zoran *zr;
+
+	for (i = 0; i < zoran_num; i++) {
+		zr = &zoran[i];
+
+		if (!zr->initialized)
+			continue;
+
+		/* unregister i2c_bus */
+		i2c_unregister_bus((&zr->i2c));
+
+		/* disable PCI bus-mastering */
+		pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command);
+		command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command);
+
+		/* put chip into reset */
+		btwrite(0, ZR36057_SPGPPCR);
+
+		free_irq(zr->pci_dev->irq, zr);
+
+		/* unmap and free memory */
+
+		kfree((void *) zr->stat_com);
+
+		iounmap(zr->zr36057_mem);
+
+		video_unregister_device(&zr->video_dev);
+	}
+}
+
+/*
+ *   Scan for a Buz card (actually for the PCI controller ZR36057),
+ *   request the irq and map the io memory
+ */
+
+static int find_zr36057(void)
+{
+	unsigned char latency;
+	struct zoran *zr;
+	struct pci_dev *dev = NULL;
+
+	zoran_num = 0;
+
+	while (zoran_num < BUZ_MAX
+	       && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
+		zr = &zoran[zoran_num];
+		zr->pci_dev = dev;
+		zr->zr36057_mem = NULL;
+		zr->id = zoran_num;
+		sprintf(zr->name, "zoran%u", zr->id);
+
+		spin_lock_init(&zr->lock);
+
+		zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+		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",
+			       zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
+		} else {
+			unsigned short ss_vendor_id, ss_id;
+
+			pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor_id);
+			pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_ID, &ss_id);
+			printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
+			       zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
+			printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n",
+			       zr->name, ss_vendor_id, ss_id);
+			if(ss_vendor_id==0xFF10 && ss_id == 0xDE41)
+			{
+				zr->board = BOARD_LML33;
+				printk(KERN_INFO "%s: LML33 detected.\n", zr->name);
+			}
+		}
+
+		zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000);
+
+		/* set PCI latency timer */
+		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
+		if (latency != 48) {
+			printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency);
+			latency = 48;
+			pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency);
+		}
+		zoran_num++;
+	}
+	if (zoran_num == 0)
+		printk(KERN_INFO "zoran: no cards found.\n");
+
+	return zoran_num;
+}
+
+#include "chipsets.h"
+
+static void handle_chipset(void)
+{
+	int index;
+	struct pci_dev *dev = NULL;
+
+	for (index = 0; index < sizeof(black) / sizeof(black[0]); index++) {
+		if ((dev = pci_find_device(black[index].vendor, black[index].device, dev)) != NULL) {
+			printk(KERN_INFO ": Host bridge: %s, ", black[index].name);
+			switch (black[index].action) {
+
+			case TRITON:
+				printk("enabling Triton support.\n");
+				triton = 1;
+				break;
+
+			case NATOMA:
+				printk("enabling Natoma workaround.\n");
+				natoma = 1;
+				break;
+			}
+		}
+	}
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+int init_zoran_cards(struct video_init *unused)
+#endif
+{
+	int i;
+
+
+	printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n");
+
+	/* Look for Buz cards */
+
+	if (find_zr36057() <= 0) {
+		return -EIO;
+	}
+	printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num);
+
+	if (zoran_num == 0)
+		return -ENXIO;
+
+	
+	/* check the parameters we have been given, adjust if necessary */
+
+	if (v4l_nbufs < 0)
+		v4l_nbufs = 0;
+	if (v4l_nbufs > VIDEO_MAX_FRAME)
+		v4l_nbufs = VIDEO_MAX_FRAME;
+	/* The user specfies the in KB, we want them in byte (and page aligned) */
+	v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
+	if (v4l_bufsize < 32768)
+		v4l_bufsize = 32768;
+	/* 2 MB is arbitrary but sufficient for the maximum possible images */
+	if (v4l_bufsize > 2048 * 1024)
+		v4l_bufsize = 2048 * 1024;
+
+	printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10);
+
+	/* Use parameter for vidmem or try to find a video card */
+
+	if (vidmem) {
+		printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem);
+	}
+
+	/* check if we have a Triton or Natome chipset */
+
+	handle_chipset();
+
+	/* take care of Natoma chipset and a revision 1 zr36057 */
+
+	for (i = 0; i < zoran_num; i++) {
+		if (natoma && zoran[i].revision <= 1) {
+			zoran[i].need_contiguous = 1;
+			printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name);
+		} else {
+			zoran[i].need_contiguous = 0;
+		}
+	}
+
+	/* initialize the Buzs */
+
+	/* We have to know which ones must be released if an error occurs */
+	for (i = 0; i < zoran_num; i++)
+		zoran[i].initialized = 0;
+
+	for (i = 0; i < zoran_num; i++) {
+		if (zr36057_init(i) < 0) {
+			release_zoran();
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	release_zoran();
+}
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/buz.h linux/drivers/char/buz.h
--- v2.3.9/linux/drivers/char/buz.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/buz.h	Mon Jul  5 20:07:02 1999
@@ -0,0 +1,319 @@
+/* 
+   buz - Iomega Buz driver
+
+   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+   based on
+
+   buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   and
+
+   bttv - Bt848 frame grabber driver
+   Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+   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.
+ */
+
+#ifndef _BUZ_H_
+#define _BUZ_H_
+
+/* The Buz only supports a maximum width of 720, but some V4L
+   applications (e.g. xawtv are more happy with 768).
+   If XAWTV_HACK is defined, we try to fake a device with bigger width */
+
+#define XAWTV_HACK
+
+#ifdef XAWTV_HACK
+#define   BUZ_MAX_WIDTH   768	/* never display more than 768 pixels */
+#else
+#define   BUZ_MAX_WIDTH   720	/* never display more than 720 pixels */
+#endif
+#define   BUZ_MAX_HEIGHT  576	/* never display more than 576 rows */
+#define   BUZ_MIN_WIDTH    32	/* never display less than 32 pixels */
+#define   BUZ_MIN_HEIGHT   24	/* never display less than 24 rows */
+
+struct zoran_requestbuffers {
+	unsigned long count;	/* Number of buffers for MJPEG grabbing */
+	unsigned long size;	/* Size PER BUFFER in bytes */
+};
+
+struct zoran_sync {
+	unsigned long frame;	/* number of buffer that has been free'd */
+	unsigned long length;	/* number of code bytes in buffer (capture only) */
+	unsigned long seq;	/* frame sequence number */
+	struct timeval timestamp;	/* timestamp */
+};
+
+struct zoran_status {
+	int input;		/* Input channel, has to be set prior to BUZIOC_G_STATUS */
+	int signal;		/* Returned: 1 if valid video signal detected */
+	int norm;		/* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int color;		/* Returned: 1 if color signal detected */
+};
+
+struct zoran_params {
+
+	/* The following parameters can only be queried */
+
+	int major_version;	/* Major version number of driver */
+	int minor_version;	/* Minor version number of driver */
+
+	/* Main control parameters */
+
+	int input;		/* Input channel: 0 = Composite, 1 = S-VHS */
+	int norm;		/* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int decimation;		/* decimation of captured video,
+				   enlargement of video played back.
+				   Valid values are 1, 2, 4 or 0.
+				   0 is a special value where the user
+				   has full control over video scaling */
+
+	/* The following parameters only have to be set if decimation==0,
+	   for other values of decimation they provide the data how the image is captured */
+
+	int HorDcm;		/* Horizontal decimation: 1, 2 or 4 */
+	int VerDcm;		/* Vertical decimation: 1 or 2 */
+	int TmpDcm;		/* Temporal decimation: 1 or 2,
+				   if TmpDcm==2 in capture every second frame is dropped,
+				   in playback every frame is played twice */
+	int field_per_buff;	/* Number of fields per buffer: 1 or 2 */
+	int img_x;		/* start of image in x direction */
+	int img_y;		/* start of image in y direction */
+	int img_width;		/* image width BEFORE decimation,
+				   must be a multiple of HorDcm*16 */
+	int img_height;		/* image height BEFORE decimation,
+				   must be a multiple of VerDcm*8 */
+
+	/* --- End of parameters for decimation==0 only --- */
+
+	/* JPEG control parameters */
+
+	int quality;		/* Measure for quality of compressed images.
+				   Scales linearly with the size of the compressed images.
+				   Must be beetween 0 and 100, 100 is a compression
+				   ratio of 1:4 */
+
+	int odd_even;		/* Which field should come first ??? */
+
+	int APPn;		/* Number of APP segment to be written, must be 0..15 */
+	int APP_len;		/* Length of data in JPEG APPn segment */
+	char APP_data[60];	/* Data in the JPEG APPn segment. */
+
+	int COM_len;		/* Length of data in JPEG COM segment */
+	char COM_data[60];	/* Data in JPEG COM segment */
+
+	unsigned long jpeg_markers;	/* Which markers should go into the JPEG output.
+					   Unless you exactly know what you do, leave them untouched.
+					   Inluding less markers will make the resulting code
+					   smaller, but there will be fewer aplications
+					   which can read it.
+					   The presence of the APP and COM marker is
+					   influenced by APP0_len and COM_len ONLY! */
+#define JPEG_MARKER_DHT (1<<3)	/* Define Huffman Tables */
+#define JPEG_MARKER_DQT (1<<4)	/* Define Quantization Tables */
+#define JPEG_MARKER_DRI (1<<5)	/* Define Restart Interval */
+#define JPEG_MARKER_COM (1<<6)	/* Comment segment */
+#define JPEG_MARKER_APP (1<<7)	/* App segment, driver will allways use APP0 */
+
+	int VFIFO_FB;		/* Flag for enabling Video Fifo Feedback.
+				   If this flag is turned on and JPEG decompressing
+				   is going to the screen, the decompress process
+				   is stopped every time the Video Fifo is full.
+				   This enables a smooth decompress to the screen
+				   but the video output signal will get scrambled */
+
+	/* Misc */
+
+	char reserved[312];	/* Makes 512 bytes for this structure */
+};
+
+/*
+   Private IOCTL to set up for displaying MJPEG
+ */
+#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct zoran_params)
+#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct zoran_params)
+#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct zoran_requestbuffers)
+#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
+#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
+#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct zoran_sync)
+#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct zoran_status)
+
+
+#ifdef __KERNEL__
+
+#define BUZ_NUM_STAT_COM    4
+#define BUZ_MASK_STAT_COM   3
+
+#define BUZ_MAX_FRAME     256	/* Must be a power of 2 */
+#define BUZ_MASK_FRAME    255	/* Must be BUZ_MAX_FRAME-1 */
+
+#if VIDEO_MAX_FRAME <= 32
+#define   V4L_MAX_FRAME   32
+#elif VIDEO_MAX_FRAME <= 64
+#define   V4L_MAX_FRAME   64
+#else
+#error   "Too many video frame buffers to handle"
+#endif
+#define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
+
+
+#include "zr36057.h"
+
+enum zoran_codec_mode {
+	BUZ_MODE_IDLE,		/* nothing going on */
+	BUZ_MODE_MOTION_COMPRESS,	/* grabbing frames */
+	BUZ_MODE_MOTION_DECOMPRESS,	/* playing frames */
+	BUZ_MODE_STILL_COMPRESS,	/* still frame conversion */
+	BUZ_MODE_STILL_DECOMPRESS	/* still frame conversion */
+};
+
+enum zoran_buffer_state {
+	BUZ_STATE_USER,		/* buffer is owned by application */
+	BUZ_STATE_PEND,		/* buffer is queued in pend[] ready to feed to I/O */
+	BUZ_STATE_DMA,		/* buffer is queued in dma[] for I/O */
+	BUZ_STATE_DONE		/* buffer is ready to return to application */
+};
+
+struct zoran_gbuffer {
+	u32 *frag_tab;		/* addresses of frag table */
+	u32 frag_tab_bus;	/* same value cached to save time in ISR */
+	enum zoran_buffer_state state;	/* non-zero if corresponding buffer is in use in grab queue */
+	struct zoran_sync bs;	/* DONE: info to return to application */
+};
+
+struct v4l_gbuffer {
+	char *fbuffer;		/* virtual  address of frame buffer */
+	unsigned long fbuffer_phys;	/* physical address of frame buffer */
+	unsigned long fbuffer_bus;	/* bus      address of frame buffer */
+	enum zoran_buffer_state state;	/* state: unused/pending/done */
+};
+
+struct zoran {
+	struct video_device video_dev;
+	struct i2c_bus i2c;
+
+	int initialized;	/* flag if zoran has been correctly initalized */
+	int user;		/* number of current users (0 or 1) */
+
+	unsigned short id;	/* number of this device */
+	char name[32];		/* name of this device */
+	struct pci_dev *pci_dev;	/* PCI device */
+	unsigned char revision;		/* revision of zr36057 */
+	int board;			/* Board type */
+#define BOARD_BUZ		0
+#define BOARD_LML33		1	
+	unsigned int zr36057_adr;	/* bus address of IO mem returned by PCI BIOS */
+	unsigned char *zr36057_mem;	/* pointer to mapped IO memory */
+
+	int map_mjpeg_buffers;	/* Flag which bufferset will map by next mmap() */
+
+	spinlock_t lock;	/* Spinlock */
+
+	/* Video for Linux parameters */
+
+	struct video_picture picture;	/* Current picture params */
+	struct video_buffer buffer;	/* Current buffer params */
+	struct video_window window;	/* Current window params */
+	int buffer_set, window_set;	/* Flags if the above structures are set */
+	int video_interlace;	/* Image on screen is interlaced */
+
+	u32 *overlay_mask;
+
+	wait_queue_head_t v4l_capq;	/* wait here for grab to finish */
+
+	int v4l_overlay_active;	/* Overlay grab is activated */
+	int v4l_memgrab_active;	/* Memory grab is activated */
+
+	int v4l_grab_frame;	/* Frame number being currently grabbed */
+#define NO_GRAB_ACTIVE (-1)
+	int v4l_grab_seq;	/* Number of frames grabbed */
+	int gwidth;		/* Width of current memory capture */
+	int gheight;		/* Height of current memory capture */
+	int gformat;		/* Format of ... */
+	int gbpl;		/* byte per line of ... */
+
+	/* V4L grab queue of frames pending */
+
+	unsigned v4l_pend_head;
+	unsigned v4l_pend_tail;
+	int v4l_pend[V4L_MAX_FRAME];
+
+	struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME];	/* V4L   buffers' info */
+
+	/* Buz MJPEG parameters */
+
+	unsigned long jpg_nbufs;	/* Number of buffers */
+	unsigned long jpg_bufsize;	/* Size of mjpeg buffers in bytes */
+	int jpg_buffers_allocated;	/* Flag if buffers are allocated  */
+	int need_contiguous;	/* Flag if contiguous buffers are needed */
+
+	enum zoran_codec_mode codec_mode;		/* status of codec */
+	struct zoran_params params;	/* structure with a lot of things to play with */
+
+	wait_queue_head_t  jpg_capq;	/* wait here for grab to finish */
+
+	/* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */
+	/* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */
+	/* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */
+	unsigned long jpg_que_head;	/* Index where to put next buffer which is queued */
+	unsigned long jpg_dma_head;	/* Index of next buffer which goes into stat_com  */
+	unsigned long jpg_dma_tail;	/* Index of last buffer in stat_com               */
+	unsigned long jpg_que_tail;	/* Index of last buffer in queue                  */
+	unsigned long jpg_seq_num;	/* count of frames since grab/play started */
+
+	/* zr36057's code buffer table */
+	u32 *stat_com;		/* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+
+	/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
+	int jpg_pend[BUZ_MAX_FRAME];
+
+	/* array indexed by frame number */
+	struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME];	/* MJPEG buffers' info */
+};
+
+#endif
+
+/*The following should be done in more portable way. It depends on define
+   of _ALPHA_BUZ in the Makefile. */
+
+#ifdef _ALPHA_BUZ
+#define btwrite(dat,adr)    writel((dat),(char *) (zr->zr36057_adr+(adr)))
+#define btread(adr)         readl(zr->zr36057_adr+(adr))
+#else
+#define btwrite(dat,adr)    writel((dat), (char *) (zr->zr36057_mem+(adr)))
+#define btread(adr)         readl(zr->zr36057_mem+(adr))
+#endif
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#define I2C_TSA5522        0xc2
+#define I2C_TDA9850        0xb6
+#define I2C_HAUPEE         0xa0
+#define I2C_STBEE          0xae
+#define   I2C_SAA7111        0x48
+#define   I2C_SAA7185        0x88
+
+#define TDA9850_CON1       0x04
+#define TDA9850_CON2       0x05
+#define TDA9850_CON3       0x06
+#define TDA9850_CON4       0x07
+#define TDA9850_ALI1       0x08
+#define TDA9850_ALI2       0x09
+#define TDA9850_ALI3       0x0a
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c
--- v2.3.9/linux/drivers/char/bw-qcam.c	Fri Mar 26 13:57:41 1999
+++ linux/drivers/char/bw-qcam.c	Mon Jul  5 20:07:02 1999
@@ -159,6 +159,8 @@
 	struct qcam_device *q;
 	
 	q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
+	if(q==NULL)
+		return NULL;
 
 	q->pport = port;
 	q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
@@ -1045,7 +1047,7 @@
 		close_bwqcam(qcams[i]);
 }
 #else
-__initfunc(int init_bw_qcams(struct video_init *unused))
+int __init init_bw_qcams(struct video_init *unused)
 {
 	struct parport *port;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c
--- v2.3.9/linux/drivers/char/c-qcam.c	Wed Dec 16 12:53:13 1998
+++ linux/drivers/char/c-qcam.c	Mon Jul  5 20:07:02 1999
@@ -1,6 +1,6 @@
 /*
  *	Video4Linux Colour QuickCam driver
- *	Copyright 1997-1998 Philip Blundell <philb@gnu.org>
+ *	Copyright 1997-1999 Philip Blundell <philb@gnu.org>
  *
  */
 
@@ -294,7 +294,7 @@
 	if (is_bi_dir)
 	{
 		/* Turn the port around */
-		parport_frob_control(q->pport, 0x20, 0x20);
+		parport_data_reverse(q->pport);
 		mdelay(3);
 		qcam_set_ack(q, 0);
 		if (qcam_await_ready1(q, 1)) {
@@ -336,7 +336,7 @@
 	{
 		printk("qcam: short read.\n");
 		if (is_bi_dir)
-			parport_frob_control(q->pport, 0x20, 0);
+			parport_data_forward(q->pport);
 		qc_setup(q);
 		return len;
 	}
@@ -355,11 +355,11 @@
 		if (qcam_await_ready1(q, 1))
 		{
 			printk("qcam: no ack after EOF\n");
-			parport_frob_control(q->pport, 0x20, 0);
+			parport_data_forward(q->pport);
 			qc_setup(q);
 			return len;
 		}
-		parport_frob_control(q->pport, 0x20, 0);
+		parport_data_forward(q->pport);
 		mdelay(3);
 		qcam_set_ack(q, 1);
 		if (qcam_await_ready1(q, 0))
@@ -641,12 +641,14 @@
 	struct qcam_device *q;
 	
 	q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
+	if(q==NULL)
+		return NULL;
 
 	q->pport = port;
 	q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
 					  NULL, 0, NULL);
 
-	q->bidirectional = (q->pport->modes & PARPORT_MODE_PCPS2)?1:0;
+	q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
 
 	if (q->pdev == NULL) 
 	{
@@ -678,10 +680,7 @@
 	struct qcam_device *qcam;
 
 	if (num_cams == MAX_CAMS)
-	{
-		printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
 		return -ENOSPC;
-	}
 
 	qcam = qcam_init(port);
 	if (qcam==NULL)
@@ -725,19 +724,40 @@
 	kfree(qcam);
 }
 
-#define BANNER "Connectix Colour Quickcam driver v0.02\n"
+#define BANNER "Connectix Colour Quickcam driver v0.03"
 
-#ifdef MODULE
-int init_module(void)
+static void cq_attach(struct parport *port)
+{
+	init_cqcam(port);
+}
+
+static void cq_detach(struct parport *port)
+{
+	/* Write this some day. */
+}
+
+static struct parport_driver cqcam_driver = {
+	"cqcam",
+	cq_attach,
+	cq_detach,
+	NULL
+};
+
+static void cqcam_init(void)
 {
-	struct parport *port;
+	printk(BANNER "\n");
+	parport_register_driver(&cqcam_driver);
+}
 
-	printk(BANNER);
+#ifdef MODULE
 
-	for (port = parport_enumerate(); port; port=port->next)
-		init_cqcam(port);
+MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
+MODULE_DESCRIPTION(BANNER);
 
-	return (num_cams)?0:-ENODEV;
+int init_module(void)
+{
+	cqcam_init();
+	return 0;
 }
 
 void cleanup_module(void)
@@ -747,14 +767,9 @@
 		close_cqcam(qcams[i]);
 }
 #else
-__initfunc(int init_colour_qcams(struct video_init *unused))
+int __init init_colour_qcams(struct video_init *unused)
 {
-	struct parport *port;
-
-	printk(BANNER);
-
-	for (port = parport_enumerate(); port; port=port->next)
-		init_cqcam(port);
+	cqcam_init();
 	return 0;
 }
 #endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/chipsets.h linux/drivers/char/chipsets.h
--- v2.3.9/linux/drivers/char/chipsets.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/chipsets.h	Mon Jul  5 20:07:02 1999
@@ -0,0 +1,41 @@
+static const struct {
+	unsigned short vendor;
+	unsigned short device;
+	enum {
+		TRITON,
+		NATOMA
+	} action;
+	const char *name;
+} black[] = {
+
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, TRITON, "82437"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, TRITON, "82437VX Triton II"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, TRITON, "82439HX Triton II"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, TRITON, "82439TX"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, NATOMA, "82441FX Natoma"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, NATOMA, "440LX - 82443LX PAC Host"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, NATOMA, "440LX - 82443LX PAC AGP"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, NATOMA, "440BX - 82443BX Host"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, NATOMA, "440BX - 82443BX AGP"
+	},
+	{
+		PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, NATOMA, "440BX - 82443BX Host (no AGP)"
+	},
+};
diff -u --recursive --new-file v2.3.9/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.3.9/linux/drivers/char/console.c	Tue May 11 14:37:40 1999
+++ linux/drivers/char/console.c	Tue Jul  6 19:16:55 1999
@@ -2282,7 +2282,7 @@
 struct tty_driver console_driver;
 static int console_refcount;
 
-__initfunc(unsigned long con_init(unsigned long kmem_start))
+unsigned long __init con_init(unsigned long kmem_start)
 {
 	const char *display_desc = NULL;
 	unsigned int currcons = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- v2.3.9/linux/drivers/char/consolemap.c	Tue Dec 29 14:28:37 1998
+++ linux/drivers/char/consolemap.c	Tue Jul  6 19:16:55 1999
@@ -671,8 +671,8 @@
  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
  * from this function, hence the call from sys_setup.
  */
-__initfunc(void
-console_map_init(void))
+void __init 
+console_map_init(void)
 {
 	int i;
 	
diff -u --recursive --new-file v2.3.9/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.3.9/linux/drivers/char/cyclades.c	Mon May 24 22:38:07 1999
+++ linux/drivers/char/cyclades.c	Tue Jul  6 19:05:48 1999
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define	Z_WAKE
 static char rcsid[] =
-"$Revision: 2.2.2.2 $$Date: 1999/05/21 17:18:15 $";
+"$Revision: 2.2.2.3 $$Date: 1999/06/28 11:13:29 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -31,6 +31,16 @@
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.2.3   1999/06/28 11:13:29 ivan
+ * Added support for interrupt mode operation for the Z cards;
+ * Removed the driver inactivity control for the Z;
+ * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when 
+ * the Z firmware is not loaded yet;
+ * Replaced the "manual" Z Tx flush buffer by a call to a FW command of 
+ * same functionality;
+ * Implemented workaround for IRQ setting loss on the PCI configuration 
+ * registers after a PCI bridge EEPROM reload (affects PLX9060 only);
+ *
  * Revision 2.2.2.2  1999/05/14 17:18:15 ivan
  * /proc entry location changed to /proc/tty/driver/cyclades;
  * Added support to shared IRQ's (only for PCI boards);
@@ -528,7 +538,7 @@
    constant in the definition below. No other change is necessary to
    support more boards/ports. */
 
-#define NR_PORTS        128
+#define NR_PORTS        256
 
 #define ZE_V1_NPORTS	64
 #define ZO_V1	0
@@ -810,13 +820,15 @@
 #ifndef CONFIG_COBALT_27
 static void cy_probe(int, void *, struct pt_regs *);
 #endif /* CONFIG_COBALT_27 */
-static void cyz_poll(unsigned long);
 #ifdef CYCLOM_SHOW_STATUS
 static void show_status(int);
 #endif
 
 static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *);
 
+#ifndef CONFIG_CYZ_INTR
+static void cyz_poll(unsigned long);
+
 /* The Cyclades-Z polling cycle is defined by this variable */
 static long cyz_polling_cycle = CZ_DEF_POLL;
 
@@ -825,6 +837,7 @@
 cyz_timerlist = {
     NULL, NULL, 0, 0, cyz_poll
 };
+#endif /* CONFIG_CYZ_INTR */
 
 /**************************************************
 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
@@ -1197,7 +1210,7 @@
 
     if((cinfo = (struct cyclades_card *)dev_id) == 0){
 #ifdef CY_DEBUG_INTERRUPTS
-	printk("cy_interrupt: spurious interrupt %d\n\r", irq);
+	printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
 #endif
         return; /* spurious interrupt */
     }
@@ -1229,7 +1242,7 @@
                 }
                 if (status & CySRReceive) { /* reception interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-		    printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
+		    printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
 #endif
                     /* determine the channel & change to that context */
                     save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
@@ -1356,7 +1369,7 @@
                        is empty, we know we can always stuff a dozen
                        characters. */
 #ifdef CY_DEBUG_INTERRUPTS
-		    printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
+		    printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
 #endif
 
                     /* determine the channel & change to that context */
@@ -1636,12 +1649,285 @@
 } /* cyz_update_channel */
 #endif
 
-
+#ifdef CONFIG_CYZ_INTR
 static void
 cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+  struct tty_struct *tty;
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info;
+  static volatile struct FIRM_ID *firm_id;
+  static volatile struct ZFW_CTRL *zfw_ctrl;
+  static volatile struct BOARD_CTRL *board_ctrl;
+  static volatile struct CH_CTRL *ch_ctrl;
+  static volatile struct BUF_CTRL *buf_ctrl;
+  uclong channel;
+  ucchar cmd;
+  uclong param;
+  uclong hw_ver, fw_ver;
+  char data;
+  volatile int char_count, special_count;
+#ifdef BLOCKMOVE
+  int small_count;
+#endif
+  volatile uclong tx_put, tx_get, tx_bufsize;
+  volatile uclong rx_put, rx_get, rx_bufsize;
+
+    if((cinfo = (struct cyclades_card *)dev_id) == 0){
+#ifdef CY_DEBUG_INTERRUPTS
+	printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+#endif
+        return; /* spurious interrupt */
+    }
+
+	firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+        if (!ISZLOADED(*cinfo)) {
+#ifdef CY_DEBUG_INTERRUPTS
+	    printk("cyz_interrupt: board not yet loaded (INT %d).\n\r", irq);
+#endif
+	    return;
+	}
+
+	zfw_ctrl = (struct ZFW_CTRL *)
+	           (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+	board_ctrl = &(zfw_ctrl->board_ctrl);
+	fw_ver = cy_readl(&board_ctrl->fw_version);
+	hw_ver = cy_readl(&((struct RUNTIME_9060 *)
+                            (cinfo->ctl_addr))->mail_box_0);
+
+	while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
+	    special_count = 0;
+	    info = &cy_port[channel + cinfo->first_line];
+            if((tty = info->tty) == 0) continue;
+	    ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+	    buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+	    switch(cmd){
+	    case C_CM_PR_ERROR:
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+		*tty->flip.char_buf_ptr++ = 0;
+		special_count++;
+	        break;
+	    case C_CM_FR_ERROR:
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+		*tty->flip.char_buf_ptr++ = 0;
+		special_count++;
+	        break;
+	    case C_CM_RXBRK:
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+		*tty->flip.char_buf_ptr++ = 0;
+		special_count++;
+	        break;
+	    case C_CM_MDCD:
+		if (info->flags & ASYNC_CHECK_CD){
+		    if ((fw_ver > 241 ? 
+                          ((u_long)param) : 
+                          cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) {
+			/* SP("Open Wakeup\n"); */
+			cy_sched_event(info,
+			    Cy_EVENT_OPEN_WAKEUP);
+		    }else if(!((info->flags
+				& ASYNC_CALLOUT_ACTIVE)
+			 &&(info->flags
+			    & ASYNC_CALLOUT_NOHUP))){
+			/* SP("Hangup\n"); */
+			cy_sched_event(info,
+			    Cy_EVENT_HANGUP);
+		    }
+		}
+	        break;
+	    case C_CM_MCTS:
+		if (info->flags & ASYNC_CTS_FLOW) {
+		    if(info->tty->hw_stopped){
+			if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){
+			    /* cy_start isn't used because... 
+			       HW flow is handled by the board */
+			    /* SP("Write Wakeup\n"); */
+			    cy_sched_event(info,
+				Cy_EVENT_WRITE_WAKEUP);
+			}
+		    }else{
+			if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){
+			    /* cy_stop isn't used because 
+			       HW flow is handled by the board */
+			    /* SP("Write stop\n"); */
+			}
+		    }
+		}
+	        break;
+	    case C_CM_MRI:
+	        break;
+	    case C_CM_MDSR:
+	        break;
+#ifdef Z_WAKE
+	    case C_CM_IOCTLW:
+		cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+	        break;
+#endif
+	    case C_CM_RXHIWM:
+	    case C_CM_RXNNDT:
+		/* Reception Interrupt */
+#ifdef CY_DEBUG_INTERRUPTS
+	    printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r", 
+		info->card, channel);
+#endif
+
+	    rx_get = cy_readl(&buf_ctrl->rx_get);
+	    rx_put = cy_readl(&buf_ctrl->rx_put);
+	    rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
+	    if (rx_put >= rx_get)
+	    	char_count = rx_put - rx_get;
+	    else
+	    	char_count = rx_put - rx_get + rx_bufsize;
+
+	    if ( char_count ){
+
+#ifdef CY_ENABLE_MONITORING
+		info->mon.int_count++;
+		info->mon.char_count += char_count;
+		if (char_count > info->mon.char_max)
+		   info->mon.char_max = char_count;
+		info->mon.char_last = char_count;
+#endif
+		info->idle_stats.recv_bytes += char_count;
+		info->idle_stats.recv_idle   = jiffies;
+		if( tty == 0){
+		    /* flush received characters */
+		    rx_get = (rx_get + char_count) & (rx_bufsize - 1);
+		    /* SP("-"); */
+		    info->rflush_count++;
+		}else{
+#ifdef BLOCKMOVE
+		/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+		   for performance, but because of buffer boundaries, there
+		   may be several steps to the operation */
+		    while(0 < (small_count
+			= cy_min((rx_bufsize - rx_get),
+			         cy_min((TTY_FLIPBUF_SIZE - tty->flip.count),
+				        char_count)))){
+
+			memcpy_fromio(tty->flip.char_buf_ptr,
+			              (char *)(cinfo->base_addr
+				       + cy_readl(&buf_ctrl->rx_bufaddr)
+				       + rx_get),
+			              small_count);
+
+			tty->flip.char_buf_ptr += small_count;
+			memset(tty->flip.flag_buf_ptr,
+			       TTY_NORMAL,
+			       small_count);
+			tty->flip.flag_buf_ptr += small_count;
+			rx_get = (rx_get + small_count) & (rx_bufsize - 1);
+			char_count -= small_count;
+			tty->flip.count += small_count;
+		    }
+#else
+		    while(char_count--){
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+				break;
+			}
+			data = cy_readb(cinfo->base_addr +
+			           cy_readl(&buf_ctrl->rx_bufaddr) + rx_get);
+			rx_get = (rx_get + 1) & (rx_bufsize - 1);
+			tty->flip.count++;
+			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+			*tty->flip.char_buf_ptr++ = data;
+		    }
+#endif
+		    queue_task(&tty->flip.tqueue, &tq_timer);
+		}
+		/* Update rx_get */
+		cy_writel(&buf_ctrl->rx_get, rx_get);
+	    }
+		break;
+	    case C_CM_TXBEMPTY:
+	    case C_CM_TXLOWWM:
+	    case C_CM_INTBACK:
+		/* Transmission Interrupt */
+#ifdef CY_DEBUG_INTERRUPTS
+	    printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r", 
+		info->card, channel);
+#endif
+
+	    tx_get = cy_readl(&buf_ctrl->tx_get);
+	    tx_put = cy_readl(&buf_ctrl->tx_put);
+	    tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+	    if (tx_put >= tx_get)
+	    	char_count = tx_get - tx_put - 1 + tx_bufsize;
+	    else
+	    	char_count = tx_get - tx_put - 1;
+
+	    if ( char_count ){
+
+		if( tty == 0 ){
+		    goto ztxdone;
+		}
+
+		if(info->x_char) { /* send special char */
+		    data = info->x_char;
+
+		    cy_writeb((cinfo->base_addr +
+		              cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data);
+		    tx_put = (tx_put + 1) & (tx_bufsize - 1);
+		    info->x_char = 0;
+		    char_count--;
+		}
+#ifdef BLOCKMOVE
+		while(0 < (small_count
+		    = cy_min((tx_bufsize - tx_put),
+			     cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail),
+			             cy_min(info->xmit_cnt, char_count))))){
+
+		    memcpy_toio((char *)(cinfo->base_addr
+			         + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put),
+			        &info->xmit_buf[info->xmit_tail],
+			        small_count);
+
+		    tx_put = (tx_put + small_count) & (tx_bufsize - 1);
+		    char_count -= small_count;
+		    info->xmit_cnt -= small_count;
+		    info->xmit_tail =
+		       (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
+		}
+#else
+		while (info->xmit_cnt && char_count){
+		    data = info->xmit_buf[info->xmit_tail];
+		    info->xmit_cnt--;
+		    info->xmit_tail =
+			(info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+
+		    cy_writeb(cinfo->base_addr +
+		              cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, 
+			      data);
+		    tx_put = (tx_put + 1) & (tx_bufsize - 1);
+		    char_count--;
+		}
+
+#endif
+	    ztxdone:
+		if (info->xmit_cnt < WAKEUP_CHARS) {
+		    cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+		}
+		/* Update tx_put */
+		cy_writel(&buf_ctrl->tx_put, tx_put);
+	    }
+		break;
+	    case C_CM_FATAL:
+		/* should do something with this !!! */
+	        break;
+	    }
+	    if(special_count){
+		queue_task(&tty->flip.tqueue, &tq_timer);
+	    }
+	}
+
+    return;
 } /* cyz_interrupt */
 
+#else /* CONFIG_CYZ_INTR */
 
 static void
 cyz_poll(unsigned long arg)
@@ -1675,7 +1961,6 @@
 
 	firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
         if (!ISZLOADED(*cinfo)) {
-	    cinfo->inact_ctrl = 0;
 	    continue;
 	}
 
@@ -1686,12 +1971,6 @@
 	hw_ver = cy_readl(&((struct RUNTIME_9060 *)
                             (cinfo->ctl_addr))->mail_box_0);
 
-	/* Enables the firmware inactivity control */
-	if ((fw_ver > 0x00000310L) && (!cinfo->inact_ctrl)) {
-	    param = cyz_issue_cmd( &cy_card[card], 0L, C_CM_TINACT, 0L);
-	    cinfo->inact_ctrl = 1;
-	}
-
 	while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1){
 	    char_count = 0;
 	    info = &cy_port[ channel + cinfo->first_line ];
@@ -1922,17 +2201,13 @@
 	}
 	/* poll every 40 ms */
 	cyz_timerlist.expires = jiffies + cyz_polling_cycle;
-
-	/* refresh inactivity counter */
-	if (cinfo->inact_ctrl) {
-		cy_writel(&board_ctrl->inactivity, (uclong) ZF_TINACT);
-	}
     }
     add_timer(&cyz_timerlist);
 
     return;
 } /* cyz_poll */
 
+#endif /* CONFIG_CYZ_INTR */
 
 /********** End of block of Cyclades-Z specific code *********/
 /***********************************************************/
@@ -2053,12 +2328,27 @@
 
 	cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
 #ifdef Z_WAKE
+#ifdef CONFIG_CYZ_INTR
 	cy_writel(&ch_ctrl[channel].intr_enable, 
-		  C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW);
+		  C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
+		  C_IN_IOCTLW|
+		  C_IN_MDCD|C_IN_MCTS);
 #else
 	cy_writel(&ch_ctrl[channel].intr_enable, 
+		  C_IN_IOCTLW|
 		  C_IN_MDCD|C_IN_MCTS);
-#endif
+#endif /* CONFIG_CYZ_INTR */
+#else
+#ifdef CONFIG_CYZ_INTR
+	cy_writel(&ch_ctrl[channel].intr_enable, 
+		  C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
+		  C_IN_MDCD|C_IN_MCTS);
+#else
+	cy_writel(&ch_ctrl[channel].intr_enable, 
+		  C_IN_MDCD|C_IN_MCTS);
+#endif /* CONFIG_CYZ_INTR */
+#endif /* Z_WAKE */
+
 	retval = cyz_issue_cmd( &cy_card[card],
 	    channel, C_CM_IOCTL, 0L);	/* was C_CM_RESET */
 	if (retval != 0){
@@ -2126,11 +2416,21 @@
                cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
 	restore_flags(flags);
     } else {
+#ifdef CONFIG_CYZ_INTR
+      int retval;
+
+	save_flags(flags); cli();
+	    retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L);
+	    if (retval != 0){
+		printk("cyc:start_xmit retval was %x\n", retval);
+	    }
+	restore_flags(flags);
+#else /* CONFIG_CYZ_INTR */
 	/* Don't have to do anything at this time */
+#endif /* CONFIG_CYZ_INTR */
     }
 } /* start_xmit */
 
-
 /*
  * This routine shuts down a serial port; interrupts are disabled,
  * and DTR is dropped if the hangup on close termio flag is on.
@@ -2504,8 +2804,24 @@
 	    } else {
 		printk("cyc:Cyclades-Z firmware not yet loaded\n");
 	    }
+	    MOD_DEC_USE_COUNT;
 	    return -ENODEV;
 	}
+#ifdef CONFIG_CYZ_INTR
+	else {
+	    /* In case this Z board is operating in interrupt mode, its 
+	       interrupts should be enabled as soon as the first open happens 
+	       to one of its ports. */
+	    if (!cy_card[info->card].intr_enabled) {
+		retval = cyz_issue_cmd(&cy_card[info->card], 
+					0, C_CM_IRQ_ENBL, 0L);
+		if (retval != 0){
+		    printk("cyc:IRQ enable retval was %x\n", retval);
+		}
+		cy_card[info->card].intr_enabled = 1;
+	    }
+	}
+#endif /* CONFIG_CYZ_INTR */
     }
 #ifdef CY_DEBUG_OTHER
     printk("cyc:cy_open ttyC%d\n", info->line); /* */
@@ -2640,7 +2956,6 @@
 	    printk("Not clean (jiff=%lu)...", jiffies);
 #endif
 	    current->state = TASK_INTERRUPTIBLE;
-	    current->counter = 0;	/* make us low-priority */
 	    schedule_timeout(char_time);
 	    if (signal_pending(current))
 		break;
@@ -2653,7 +2968,6 @@
     }
     /* Run one more char cycle */
     current->state = TASK_INTERRUPTIBLE;
-    current->counter = 0;	/* make us low-priority */
     schedule_timeout(char_time * 5);
     current->state = TASK_RUNNING;
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
@@ -3798,14 +4112,14 @@
 	if (break_state == -1) {
 	    if (!info->breakon) {
 		info->breakon = 1;
-		if (!info->xmit_cnt ) {
+		if (!info->xmit_cnt) {
 		    start_xmit(info);
 		}
 	    }
 	} else {
 	    if (!info->breakoff) {
 		info->breakoff = 1;
-		if (!info->xmit_cnt ) {
+		if (!info->xmit_cnt) {
 		    start_xmit(info);
 		}
 	    }
@@ -4053,6 +4367,7 @@
 	case CYGETCD1400VER:
 	    ret_val = info->chip_rev;
 	    break;
+#ifndef CONFIG_CYZ_INTR
 	case CYZSETPOLLCYCLE:
             cyz_polling_cycle = (arg * HZ) / 1000;
 	    ret_val = 0;
@@ -4060,6 +4375,7 @@
 	case CYZGETPOLLCYCLE:
             ret_val = (cyz_polling_cycle * 1000) / HZ;
 	    break;
+#endif /* CONFIG_CYZ_INTR */
 	case CYSETWAIT:
     	    info->closing_wait = (unsigned short)arg * HZ/100;
 	    ret_val = 0;
@@ -4333,7 +4649,7 @@
 cy_flush_buffer(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  int card, channel;
+  int card, channel, retval;
   unsigned long flags;
                                 
 #ifdef CY_DEBUG_IO
@@ -4351,19 +4667,10 @@
 
     if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board 
 				      buffers as well */
-	static volatile struct FIRM_ID *firm_id;
-	static volatile struct ZFW_CTRL *zfw_ctrl;
-	static volatile struct CH_CTRL *ch_ctrl;
-	static volatile struct BUF_CTRL *buf_ctrl;
-
-	firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
-	zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
-				cy_readl(&firm_id->zfwctrl_addr));
-	ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
-	buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
-	while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put))
-		cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get));
+	retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
+	if (retval != 0) {
+	    printk("cyc: flush_buffer retval was %x\n", retval);
+	}
     }
     wake_up_interruptible(&tty->write_wait);
     if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
@@ -4410,8 +4717,8 @@
 
 /* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
-__initfunc(static unsigned short
-cyy_init_card(volatile ucchar *true_base_addr,int index))
+static unsigned short __init 
+cyy_init_card(volatile ucchar *true_base_addr,int index)
 {
   unsigned int chip_number;
   volatile ucchar* base_addr;
@@ -4496,8 +4803,7 @@
  * sets global variables and return the number of ISA boards found.
  * ---------------------------------------------------------------------
  */
-__initfunc(static int
-cy_detect_isa(void))
+static int __init cy_detect_isa(void)
 {
   unsigned short	cy_isa_irq,nboard;
   volatile ucchar	*cy_isa_address;
@@ -4604,8 +4910,8 @@
  * sets global variables and return the number of PCI boards found.
  * ---------------------------------------------------------------------
  */
-__initfunc(static int
-cy_detect_pci(void))
+static int __init 
+cy_detect_pci(void)
 {
 #ifdef CONFIG_PCI
 
@@ -4872,10 +5178,11 @@
 		    return(i);
                 }
 
+#ifdef CONFIG_CYZ_INTR
                 /* allocate IRQ only if board has an IRQ */
-		if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
-		    if(request_irq(cy_pci_irq,cyz_interrupt,
-			SA_SHIRQ,"Cyclades-Z",&cy_card[j]))
+		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
+		    if(request_irq(cy_pci_irq, cyz_interrupt,
+			SA_SHIRQ, "Cyclades-Z", &cy_card[j]))
 		    {
 			printk("Could not allocate IRQ%d ",
 			    cy_pci_irq);
@@ -4884,6 +5191,7 @@
 			return(i);
 		    }
 		}
+#endif /* CONFIG_CYZ_INTR */
 
 
                 /* set cy_card */
@@ -4896,7 +5204,7 @@
 
                 /* print message */
 		/* don't report IRQ if board is no IRQ */
-		if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
 		    printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
 			j+1,(ulong)cy_pci_addr2,
 			(ulong)(cy_pci_addr2 + CyPCI_Zwin - 1),
@@ -4908,6 +5216,11 @@
 		}
                 printk("%d channels starting from port %d.\n",
 		    cy_pci_nchan,cy_next_channel);
+#ifdef CONFIG_CYZ_INTR
+		/* Enable interrupts on the PLX chip */
+		cy_writew(cy_pci_addr0+0x68,
+			cy_readw(cy_pci_addr0+0x68)|0x0900);
+#endif /* CONFIG_CYZ_INTR */
                 cy_next_channel += cy_pci_nchan;
     }
         }
@@ -4927,10 +5240,6 @@
                 (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
 	    printk("Cyclades-Z/PCI: New Cyclades-Z board.  FPGA not loaded\n");
 #endif
-	    /* The following clears the firmware id word.  This ensures
-	       that the driver will not attempt to talk to the board
-	       until it has been properly initialized.
-	     */
 		PAUSE
                 /* This must be the new Cyclades-Ze/PCI. */
                 cy_pci_nchan = ZE_V1_NPORTS;
@@ -4955,10 +5264,11 @@
 		    return(i);
                 }
 
+#ifdef CONFIG_CYZ_INTR
                 /* allocate IRQ only if board has an IRQ */
-		if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
-		    if(request_irq(cy_pci_irq,cyz_interrupt,
-			SA_SHIRQ,"Cyclades-Z",&cy_card[j]))
+		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
+		    if(request_irq(cy_pci_irq, cyz_interrupt,
+			SA_SHIRQ, "Cyclades-Z", &cy_card[j]))
 		    {
 			printk("Could not allocate IRQ%d ",
 			    cy_pci_irq);
@@ -4967,6 +5277,7 @@
 			return(i);
 		    }
 		}
+#endif /* CONFIG_CYZ_INTR */
 
                 /* set cy_card */
                 cy_card[j].base_addr = cy_pci_addr2;
@@ -4978,7 +5289,7 @@
 
                 /* print message */
 		/* don't report IRQ if board is no IRQ */
-		if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
 		    printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
 			j+1,(ulong)cy_pci_addr2,
 			(ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1),
@@ -4990,6 +5301,11 @@
 		}
                 printk("%d channels starting from port %d.\n",
 		    cy_pci_nchan,cy_next_channel);
+#ifdef CONFIG_CYZ_INTR
+		/* Enable interrupts on the PLX chip */
+		cy_writew(cy_pci_addr0+0x68,
+			cy_readw(cy_pci_addr0+0x68)|0x0900);
+#endif /* CONFIG_CYZ_INTR */
                 cy_next_channel += cy_pci_nchan;
         }
 	if (ZeIndex != 0) {
@@ -5098,8 +5414,8 @@
     extra ports are ignored.
  */
 
-__initfunc(int
-cy_init(void))
+int __init 
+cy_init(void)
 {
   struct cyclades_port  *info;
   struct cyclades_card *cinfo;
@@ -5219,6 +5535,7 @@
 		mailbox = cy_readl(&((struct RUNTIME_9060 *)
 			     cy_card[board].ctl_addr)->mail_box_0);
 		nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+		cinfo->intr_enabled = 0;
                 for (port = cinfo->first_line ;
                      port < cinfo->first_line + nports;
                      port++)
@@ -5342,15 +5659,17 @@
                 }
             }
     }
-    
-    if ( number_z_boards && !cyz_timeron){
-        cyz_timeron++;
+
+#ifndef CONFIG_CYZ_INTR
+    if (number_z_boards && !cyz_timeron){
+	cyz_timeron++;
 	cyz_timerlist.expires = jiffies + 1;
 	add_timer(&cyz_timerlist);
 #ifdef CY_PCI_DEBUG
 	printk("Cyclades-Z polling initialized\n");
 #endif
     }
+#endif /* CONFIG_CYZ_INTR */
 
 #ifdef CY_PROC
         ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0);
@@ -5377,10 +5696,12 @@
     int e1, e2;
     unsigned long flags;
 
+#ifndef CONFIG_CYZ_INTR
     if (cyz_timeron){
 	cyz_timeron = 0;
 	del_timer(&cyz_timerlist);
     }
+#endif /* CONFIG_CYZ_INTR */
 
     save_flags(flags); cli();
     remove_bh(CYCLADES_BH);
@@ -5396,6 +5717,9 @@
 
     for (i = 0; i < NR_CARDS; i++) {
         if (cy_card[i].base_addr != 0
+#ifndef CONFIG_CYZ_INTR
+	    && cy_card[i].num_chips != -1 /* not a Z card */
+#endif /* CONFIG_CYZ_INTR */
 	    && cy_card[i].irq)
         {
             free_irq(cy_card[i].irq, &cy_card[i]);
diff -u --recursive --new-file v2.3.9/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c
--- v2.3.9/linux/drivers/char/dn_keyb.c	Sat May 15 15:05:36 1999
+++ linux/drivers/char/dn_keyb.c	Tue Jul  6 19:16:55 1999
@@ -570,7 +570,7 @@
         APOLLO_MOUSE_MINOR, "apollomouse", &apollo_mouse_fops
 };
 
-__initfunc(int dn_keyb_init(void)) {
+int __init dn_keyb_init(void){
 
 /*  printk("dn_keyb_init\n"); */
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.3.9/linux/drivers/char/dsp56k.c	Sat Oct 31 11:05:37 1998
+++ linux/drivers/char/dsp56k.c	Tue Jul  6 19:16:55 1999
@@ -519,8 +519,7 @@
 
 
 /****** Init and module functions ******/
-
-__initfunc(int dsp56k_init(void))
+int __init dsp56k_init(void)
 {
 	if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
 		printk("DSP56k driver: Hardware not present\n");
diff -u --recursive --new-file v2.3.9/linux/drivers/char/dz.c linux/drivers/char/dz.c
--- v2.3.9/linux/drivers/char/dz.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/dz.c	Mon Jul  5 20:35:18 1999
@@ -16,6 +16,8 @@
  *            field from "current" - somewhere between 2.1.121 and 2.1.131
  */
 
+#define DEBUG_DZ 1
+
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
@@ -41,8 +43,10 @@
 /* for definition of struct console */
 #ifdef CONFIG_SERIAL_CONSOLE
 #define CONSOLE_LINE (3)
-#include <linux/console.h>
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ)
+#include <linux/console.h>
+#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */
 
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -54,13 +58,8 @@
 #include <asm/dec/kn01.h>
 #include <asm/dec/kn02.h>
 
-#define DEBUG_DZ 1
 #ifdef DEBUG_DZ
-#include <linux/tty.h>
-#include <linux/major.h>
 #include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/console.h>
 #include <linux/fs.h>
 #include <asm/bootinfo.h>
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.3.9/linux/drivers/char/esp.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/esp.c	Tue Jul  6 19:16:55 1999
@@ -2180,7 +2180,6 @@
 	while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
 		(serial_in(info, UART_ESI_STAT2) != 0xff)) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;
 		schedule_timeout(char_time);
 
 		if (signal_pending(current))
@@ -2526,7 +2525,7 @@
 /*
  * The serial driver boot-time initialization code!
  */
-__initfunc(int espserial_init(void))
+int __init espserial_init(void)
 {
 	int i, offset;
 	int region_start;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-init.c linux/drivers/char/ftape/lowlevel/ftape-init.c
--- v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-init.c	Tue Dec  2 09:33:16 1997
+++ linux/drivers/char/ftape/lowlevel/ftape-init.c	Tue Jul  6 19:16:55 1999
@@ -64,7 +64,7 @@
 /*  Called by modules package when installing the driver
  *  or by kernel during the initialization phase
  */
-__initfunc(int ftape_init(void))
+int __init ftape_init(void)
 {
 	TRACE_FUN(ft_t_flow);
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-proc.c linux/drivers/char/ftape/lowlevel/ftape-proc.c
--- v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-proc.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/ftape/lowlevel/ftape-proc.c	Tue Jul  6 19:16:55 1999
@@ -112,6 +112,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
@@ -420,7 +421,7 @@
 	return len;
 }
 
-__initfunc(int ftape_proc_init(void))
+int __init ftape_proc_init(void)
 {
 	return FT_PROC_REGISTER(&proc_root, &proc_ftape);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-setup.c linux/drivers/char/ftape/lowlevel/ftape-setup.c
--- v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-setup.c	Tue Nov 25 14:45:27 1997
+++ linux/drivers/char/ftape/lowlevel/ftape-setup.c	Tue Jul  6 19:16:55 1999
@@ -60,7 +60,7 @@
 	{ "mach2",     &ft_mach2,          CONFIG_FT_MACH2,          0,     1}
 };
 
-__initfunc(void ftape_setup(char *str, int *ints))
+void __init ftape_setup(char *str, int *ints)
 {
 	int i;
 	int param;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c
--- v2.3.9/linux/drivers/char/ftape/zftape/zftape-init.c	Sun Mar  7 10:42:26 1999
+++ linux/drivers/char/ftape/zftape/zftape-init.c	Tue Jul  6 19:16:55 1999
@@ -414,7 +414,7 @@
 /*  Called by modules package when installing the driver or by kernel
  *  during the initialization phase
  */
-__initfunc(int zft_init(void))
+int __init zft_init(void)
 {
 	TRACE_FUN(ft_t_flow);
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/hfmodem/main.c linux/drivers/char/hfmodem/main.c
--- v2.3.9/linux/drivers/char/hfmodem/main.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/hfmodem/main.c	Tue Jul  6 19:16:55 1999
@@ -62,7 +62,6 @@
 #if LINUX_VERSION_CODE >= 0x20100
 #include <asm/uaccess.h>
 #else
-#include <asm/segment.h>
 #include <linux/mm.h>
 
 #undef put_user
@@ -160,7 +159,7 @@
 }
 
 /* --------------------------------------------------------------------- */
-__initfunc(static int check_lpt(struct hfmodem_state *dev, unsigned int iobase))
+static int __init check_lpt(struct hfmodem_state *dev, unsigned int iobase)
 {
 	struct parport *pp = parport_enumerate();
 
@@ -179,7 +178,7 @@
 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" };
 
-__initfunc(static enum uart check_uart(unsigned int iobase))
+static enum uart __init check_uart(unsigned int iobase)
 {
         unsigned char b1,b2,b3;
         enum uart u;
@@ -215,7 +214,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(static int check_midi(unsigned int iobase))
+static int __init check_midi(unsigned int iobase)
 {
         unsigned long timeout;
         unsigned long flags;
@@ -263,7 +262,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(static void output_check(struct hfmodem_state *dev))
+static void __init output_check(struct hfmodem_state *dev)
 {
         enum uart u = c_uart_unknown;
 
@@ -625,7 +624,7 @@
 
 #endif
 
-__initfunc(int init_module(void))
+int __init init_module(void)
 {
 	int i;
 
@@ -678,7 +677,7 @@
 
 static int hw = 0;
 
-__initfunc(void hfmodem_setup(char *str, int *ints))
+void __init hfmodem_setup(char *str, int *ints)
 {
         if (ints[0] < 7) {
                 printk(KERN_WARNING "%s: setup: too few parameters\n", hfmodem_drvname);
@@ -699,7 +698,7 @@
         hfmodem_refclock_setscale(ints[ints[0]-2], ints[ints[0]-1], ints[ints[0]]);
 }
 
-__initfunc(void hfmodem_init(void))
+void __init hfmodem_init(void)
 {
         int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/hfmodem/refclock.c linux/drivers/char/hfmodem/refclock.c
--- v2.3.9/linux/drivers/char/hfmodem/refclock.c	Sat Jul 18 11:47:49 1998
+++ linux/drivers/char/hfmodem/refclock.c	Tue Jul  6 19:16:55 1999
@@ -66,7 +66,7 @@
 /* --------------------------------------------------------------------- */
 
 #ifdef __i386__
-__initfunc(static void i386_capability(void))
+static void __init i386_capability(void)
 {
 	if (boot_cpu_data.x86_capability & X86_FEATURE_TSC)
 		rdtsc_ok = 1;
@@ -77,7 +77,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(void hfmodem_refclock_probe(void))
+void __init hfmodem_refclock_probe(void)
 {
 #ifdef __i386__
 	if (rdtsc_ok) {
diff -u --recursive --new-file v2.3.9/linux/drivers/char/i2c-parport.c linux/drivers/char/i2c-parport.c
--- v2.3.9/linux/drivers/char/i2c-parport.c	Sat May 22 15:02:48 1999
+++ linux/drivers/char/i2c-parport.c	Thu Jul  1 14:22:56 1999
@@ -36,9 +36,7 @@
 
 static struct parport_i2c_bus *bus_list;
 
-#ifdef __SMP__
 static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 /* software I2C functions */
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/i2c.c linux/drivers/char/i2c.c
--- v2.3.9/linux/drivers/char/i2c.c	Thu Jan 14 22:53:02 1999
+++ linux/drivers/char/i2c.c	Mon Jul  5 20:07:02 1999
@@ -40,6 +40,14 @@
 extern int i2c_tuner_init(void);
 extern int msp3400c_init(void);
 #endif
+#ifdef CONFIG_VIDEO_BUZ
+extern int saa7111_init(void);
+extern int saa7185_init(void);
+#endif
+#ifdef CONFIG_VIDEO_LML33
+extern int bt819_init(void);
+extern int bt856_init(void);
+#endif
 
 int i2c_init(void)
 {
@@ -50,6 +58,14 @@
 	i2c_tuner_init();
 	msp3400c_init();
 #endif	
+#ifdef CONFIG_VIDEO_BUZ
+	saa7111_init();
+	saa7185_init();
+#endif
+#ifdef CONFIG_VIDEO_LML33
+	bt819_init();
+	bt856_init();
+#endif
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/joystick/joy-db9.c linux/drivers/char/joystick/joy-db9.c
--- v2.3.9/linux/drivers/char/joystick/joy-db9.c	Tue Dec  1 19:05:05 1998
+++ linux/drivers/char/joystick/joy-db9.c	Thu Jul  1 14:22:57 1999
@@ -337,7 +337,7 @@
 			return port;
 		}
 
-		if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2))) {
+		if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
 			printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
 			return port;
 		}
diff -u --recursive --new-file v2.3.9/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.3.9/linux/drivers/char/lp.c	Wed May 12 08:41:12 1999
+++ linux/drivers/char/lp.c	Thu Jul  1 14:22:57 1999
@@ -27,6 +27,9 @@
  * Obsoleted the CAREFUL flag since a printer that doesn' t work with
  * CAREFUL will block a bit after in lp_check_status().
  *				Andrea Arcangeli, 15 Oct 1998
+ * Obsoleted and removed all the lowlevel stuff implemented in the last
+ * month to use the IEEE1284 functions (that handle the _new_ compatibilty
+ * mode fine).
  */
 
 /* This driver should, in theory, work with any parallel port that has an
@@ -58,74 +61,6 @@
  *	# insmod lp.o reset=1
  */
 
-/*
- * LP OPTIMIZATIONS
- *
- * - TRUST_IRQ flag
- * 
- * Epson Stylus Color, HP and many other new printers want the TRUST_IRQ flag
- * set when printing with interrupts. This is a long story. Such printers
- * use a broken handshake (see the timing graph below) when printing with
- * interrupts. The lp driver as default is just able to handle such bogus
- * handshake, but setting such flag cause lp to go faster and probably do
- * what such printers want (even if not documented).
- *
- * NOTE that setting the TRUST_IRQ flag in some printer can cause the irq
- * printing to fail completly. You must try, to know if your printer
- * will handle it. I suggest a graphics printing to force a major flow of
- * characters to the printer for do the test. NOTE also that the TRUST_IRQ
- * flag _should_ be fine everywhere but there is a lot of buggy hardware out
- * there, so I am forced to implement it as a not-default thing.
- * WARNING: before to do the test, be sure to have not played with the
- * `-w' parameter of tunelp!
- *
- * Note also that lp automagically warn you (with a KERN_WARNING) if it
- * detects that you could _try_ to set the TRUST_IRQ flag to speed up the
- * printing and decrease the CPU load.
- *
- * To set the TRUST_IRQ flag you can use this command:
- *
- * tunelp /dev/lp? -T on
- *
- * If you have an old tunelp executable you can (hack and) use this simple
- * C lazy proggy to set the flag in the lp driver:
-
--------------------------- cut here -------------------------------------
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#define	LPTRUSTIRQ  0x060f
-
-int main(int argc, char **argv)
-{
-	int fd = open("/dev/lp0", O_RDONLY);
-	ioctl(fd, LPTRUSTIRQ, argc - 1);
-	if (argc - 1)
-		printf("trusting the irq\n");
-	else
-		printf("untrusting the irq\n");
-	return 0;
-}
--------------------------- cut here -------------------------------------
-
- * - LP_WAIT time
- *
- * You can use this setting if your printer is fast enough and/or your
- * machine is slow enough ;-).
- *
- * tunelp /dev/lp? -w 0
- *
- * - LP_CHAR tries
- *
- * If you print with irqs probably you can decrease the CPU load a lot using
- * this setting. This is not the default because the printing is reported to
- * be jerky somewhere...
- *
- * tunelp /dev/lp? -c 1
- *
- *					11 Nov 1998, Andrea Arcangeli
- */
-
 /* COMPATIBILITY WITH OLD KERNELS
  *
  * Under Linux 2.0 and previous versions, lp devices were bound to ports at
@@ -162,6 +97,15 @@
  * this case fine too.
  *
  *					15 Oct 1998, Andrea Arcangeli
+ *
+ * The so called `buggy' handshake is really the well documented
+ * compatibility mode IEEE1284 handshake. They changed the well known
+ * Centronics handshake acking in the middle of busy expecting to not
+ * break drivers or legacy application, while they broken linux lp
+ * until I fixed it reverse engineering the protocol by hand some
+ * month ago...
+ *
+ *                                     14 Dec 1998, Andrea Arcangeli
  */
 
 #include <linux/module.h>
@@ -175,6 +119,8 @@
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/console.h>
 
 #include <linux/parport.h>
 #undef LP_STATS
@@ -189,6 +135,8 @@
 
 struct lp_struct lp_table[LP_NO];
 
+static unsigned int lp_count = 0;
+
 /* Test if printer is ready */
 #define	LP_READY(status)	((status) & LP_PBUSY)
 /* Test if the printer is not acking the strobe */
@@ -197,7 +145,9 @@
 #define LP_NO_ERROR(status)	((status) & LP_PERRORP)
 
 #undef LP_DEBUG
-#undef LP_READ_DEBUG
+
+/* If you want to see if you can get lp_poll working, define this. */
+#undef SUPPORT_POLL
 
 /* --- parport support ----------------------------------------- */
 
@@ -205,15 +155,62 @@
 {
        struct lp_struct *lps = (struct lp_struct *)handle;
 
-       if (waitqueue_active (&lps->wait_q))
-               wake_up_interruptible(&lps->wait_q);
+       if (!(lps->flags & LP_PORT_BUSY)) {
+	       /* Let the port go. */
+	       clear_bit (LP_HAVE_PORT_BIT, &lps->flags);
+	       return 0;
+       }
+
+       if (!(lps->flags & LP_PORT_BUSY)) {
+	       /* Let the port go. */
+	       clear_bit (LP_HAVE_PORT_BIT, &lps->flags);
+	       return 0;
+       }
 
        /* Don't actually release the port now */
        return 1;
 }
 
-#define lp_parport_release(x)	do { parport_release(lp_table[(x)].dev); } while (0);
-#define lp_parport_claim(x)	do { parport_claim_or_block(lp_table[(x)].dev); } while (0);
+static void lp_check_data (struct lp_struct *lp)
+{
+#if !defined(CONFIG_PARPORT_1284) || !defined (SUPPORT_POLL)
+	return;
+#else
+	struct pardevice *dev = lp->dev;
+	if (!(lp->flags & LP_NO_REVERSE)) {
+		int err = parport_negotiate (dev->port, IEEE1284_MODE_NIBBLE);
+		if (err)
+			lp->flags |= LP_NO_REVERSE;
+		else {
+			unsigned char s = parport_read_status (dev->port);
+			if (s & PARPORT_STATUS_ERROR)
+				lp->flags &= ~LP_DATA_AVAIL;
+			else {
+				lp->flags |= LP_DATA_AVAIL;
+				if (waitqueue_active (&lp->dataq))
+					wake_up_interruptible (&lp->dataq);
+			}
+		}
+	}
+#endif /* IEEE 1284 support */
+}
+
+static void lp_parport_release (int minor)
+{
+	lp_check_data (&lp_table[minor]);
+	if (test_and_clear_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags))
+		parport_release (lp_table[minor].dev);
+
+	lp_table[minor].flags &= ~LP_PORT_BUSY;
+}
+
+static void lp_parport_claim (int minor)
+{
+	if (!test_and_set_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags))
+		parport_claim_or_block (lp_table[minor].dev);
+
+	lp_table[minor].flags |= LP_PORT_BUSY;
+}
 
 /* --- low-level port access ----------------------------------- */
 
@@ -222,29 +219,6 @@
 #define w_ctr(x,y)	do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0)
 #define w_dtr(x,y)	do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0)
 
-static __inline__ void lp_yield (int minor)
-{
-	if (!parport_yield_blocking (lp_table[minor].dev))
-	{
-		if (current->need_resched)
-			schedule ();
-	} else
-		lp_table[minor].irq_missed = 1;
-}
-
-static __inline__ void lp_schedule(int minor, long timeout)
-{
-	struct pardevice *dev = lp_table[minor].dev;
-	register unsigned long int timeslip = (jiffies - dev->time);
-	if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) {
-		lp_parport_release(minor);
-		lp_table[minor].irq_missed = 1;
-		schedule_timeout(timeout);
-		lp_parport_claim(minor);
-	} else
-		schedule_timeout(timeout);
-}
-
 static int lp_reset(int minor)
 {
 	int retval;
@@ -257,161 +231,51 @@
 	return retval;
 }
 
-#define	lp_wait(minor)	udelay(LP_WAIT(minor))
-
-static inline int lp_char(char lpchar, int minor)
+static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	unsigned long count = 0;
-#ifdef LP_STATS
-	struct lp_stats *stats;
-#endif
-
-	if (signal_pending(current))
-		return 0;
-
-	for (;;)
-	{
-		unsigned char status;
-		int irq_ok = 0;
-
-		/*
-		 * Give a chance to other pardevice to run in the meantime.
-		 */
-		lp_yield(minor);
-
-		status = r_str(minor);
-		if (LP_NO_ERROR(status))
-		{
-			if (LP_READY(status))
-				break;
-
-			/*
-			 * This is a crude hack that should be well known
-			 * at least by Epson device driver developers. -arca
-			 */
-			irq_ok = (!LP_POLLED(minor) &&
-				  LP_NO_ACKING(status) &&
-				  lp_table[minor].irq_detected);
-			if ((LP_F(minor) & LP_TRUST_IRQ) && irq_ok)
-				break;
-		}
-		/*
-		 * NOTE: if you run with irqs you _must_ use
-		 * `tunelp /dev/lp? -c 1' to be rasonable efficient!
-		 */
-		if (++count == LP_CHAR(minor))
-		{
-			if (irq_ok)
-			{
-				static int first_time = 1;
-				/*
-				 * The printer is using a buggy handshake, so
-				 * revert to polling to not overload the
-				 * machine and warn the user that its printer
-				 * could get optimized trusting the irq. -arca
-				 */
-				lp_table[minor].irq_missed = 1;
-				if (first_time)
-				{
-					first_time = 0;
-					printk(KERN_WARNING "lp%d: the "
-					       "printing could be optimized "
-					       "using the TRUST_IRQ flag, "
-					       "see the top of "
-					       "linux/drivers/char/lp.c\n",
-					       minor);
-				}
-			}
-			return 0;
-		}
-	}
-
-	w_dtr(minor, lpchar);
-
-#ifdef LP_STATS
-	stats = &LP_STAT(minor);
-	stats->chars++;
-#endif
+	struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
+	if (!(lp_dev->flags & LP_PORT_BUSY))
+		/* We must have the port since we got an interrupt. */
+		lp_check_data (lp_dev);
+	if (waitqueue_active (&lp_dev->waitq))
+		wake_up_interruptible (&lp_dev->waitq);
+}
 
-	/* must wait before taking strobe high, and after taking strobe
-	   low, according spec.  Some printers need it, others don't. */
-	lp_wait(minor);
+static void lp_wakeup (void *handle)
+{
+	struct lp_struct *lp_dev = handle;
 
-	/* control port takes strobe high */
-	if (LP_POLLED(minor))
-	{
-		w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-		lp_wait(minor);
-		w_ctr(minor, LP_PSELECP | LP_PINITP);
-	} else {
-		/*
-		 * Epson Stylus Color generate the IRQ on the rising edge of
-		 * strobe so clean the irq's information before playing with
-		 * the strobe. -arca
-		 */
-		lp_table[minor].irq_detected = 0;
-		lp_table[minor].irq_missed = 0;
-		/*
-		 * Be sure that the CPU doesn' t reorder instructions. -arca
-		 */
-		mb();
-		w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN);
-		lp_wait(minor);
-		w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
-	}
-
-	/*
-	 * Give to the printer a chance to put BUSY low. Really we could
-	 * remove this because we could _guess_ that we are slower to reach
-	 * again lp_char() than the printer to put BUSY low, but I' d like
-	 * to remove this variable from the function I go solve
-	 * when I read bug reports ;-). -arca
-	 */
-	lp_wait(minor);
+	if (lp_dev->flags & LP_PORT_BUSY)
+		return;
 
-#ifdef LP_STATS
-	/* update waittime statistics */
-	if (count > stats->maxwait) {
-#ifdef LP_DEBUG
-		printk(KERN_DEBUG "lp%d success after %d counts.\n",
-		       minor, count);
-#endif
-		stats->maxwait = count;
+	/* Grab the port if it can help (i.e. reverse mode is possible). */
+	if (!(lp_dev->flags & LP_NO_REVERSE)) {
+		parport_claim (lp_dev->dev);
+		set_bit (LP_HAVE_PORT_BIT, &lp_dev->flags);
+		lp_check_data (lp_dev);
+		if (waitqueue_active (&lp_dev->waitq))
+			wake_up_interruptible (&lp_dev->waitq);
 	}
-	count *= 256;
-	wait = (count > stats->meanwait) ? count - stats->meanwait :
-	    stats->meanwait - count;
-	stats->meanwait = (255 * stats->meanwait + count + 128) / 256;
-	stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
-#endif
-
-	return 1;
 }
 
-static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void lp_error (int minor)
 {
-	struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
+	int polling;
 
-	if (waitqueue_active (&lp_dev->wait_q))
-		wake_up_interruptible(&lp_dev->wait_q);
-
-	lp_dev->irq_detected = 1;
-	lp_dev->irq_missed = 0;
-}
+	if (LP_F(minor) & LP_ABORT)
+		return;
 
-static void lp_error(int minor)
-{
-	if (LP_POLLED(minor) || LP_PREEMPTED(minor)) {
-		current->state = TASK_INTERRUPTIBLE;
-		lp_parport_release(minor);
-		schedule_timeout(LP_TIMEOUT_POLLED);
-		lp_parport_claim(minor);
-		lp_table[minor].irq_missed = 1;
-	}
+	polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
+	if (polling) lp_parport_release (minor);
+	interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+					LP_TIMEOUT_POLLED);
+	if (polling) lp_parport_claim (minor);
+	else parport_yield_blocking (lp_table[minor].dev);
 }
 
 static int lp_check_status(int minor)
 {
+	int error = 0;
 	unsigned int last = lp_table[minor].last_error;
 	unsigned char status = r_str(minor);
 	if (status & LP_PERRORP)
@@ -422,155 +286,112 @@
 			last = LP_POUTPA;
 			printk(KERN_INFO "lp%d out of paper\n", minor);
 		}
+		error = -ENOSPC;
 	} else if (!(status & LP_PSELECD)) {
 		if (last != LP_PSELECD) {
 			last = LP_PSELECD;
 			printk(KERN_INFO "lp%d off-line\n", minor);
 		}
+		error = -EIO;
 	} else {
 		if (last != LP_PERRORP) {
 			last = LP_PERRORP;
 			printk(KERN_INFO "lp%d on fire\n", minor);
 		}
+		error = -EIO;
 	}
 
 	lp_table[minor].last_error = last;
 
-	if (last != 0) {
-		if (LP_F(minor) & LP_ABORT)
-			return 1;
+	if (last != 0)
 		lp_error(minor);
-	}
 
-	return 0;
+	return error;
 }
 
-static int lp_write_buf(unsigned int minor, const char *buf, int count)
+static ssize_t lp_write(struct file * file, const char * buf,
+		        size_t count, loff_t *ppos)
 {
-	unsigned long copy_size;
-	unsigned long total_bytes_written = 0;
-	unsigned long bytes_written;
-	struct lp_struct *lp = &lp_table[minor];
-
-	if (minor >= LP_NO)
-		return -ENXIO;
-	if (lp->dev == NULL)
-		return -ENXIO;
-
-	lp_table[minor].last_error = 0;
-	lp_table[minor].irq_detected = 0;
-	lp_table[minor].irq_missed = 1;
-
-	if (LP_POLLED(minor))
-		w_ctr(minor, LP_PSELECP | LP_PINITP);
-	else
-		w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
-
-	do {
-		bytes_written = 0;
-		copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
-
-		if (copy_from_user(lp->lp_buffer, buf, copy_size))
-		{
-			w_ctr(minor, LP_PSELECP | LP_PINITP);
-			return -EFAULT;
-		}
+	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	struct parport *port = lp_table[minor].dev->port;
+	char *kbuf = lp_table[minor].lp_buffer;
+	ssize_t retv = 0;
+	ssize_t written;
+	size_t copy_size = count;
 
-		while (copy_size) {
-			if (lp_char(lp->lp_buffer[bytes_written], minor)) {
-				--copy_size;
-				++bytes_written;
 #ifdef LP_STATS
-				lp->runchars++;
-#endif
-			} else {
-				int rc = total_bytes_written + bytes_written;
+	if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
+		lp_table[minor].runchars = 0;
 
-#ifdef LP_STATS
-				if (lp->runchars > LP_STAT(minor).maxrun)
-					LP_STAT(minor).maxrun = lp->runchars;
-				LP_STAT(minor).sleeps++;
+	lp_table[minor].lastcall = jiffies;
 #endif
 
-				if (signal_pending(current))
-				{
-					w_ctr(minor, LP_PSELECP | LP_PINITP);
-					if (total_bytes_written + bytes_written)
-						return total_bytes_written + bytes_written;
-					else
-						return -EINTR;
-				}
+	/* Need to copy the data from user-space. */
+	if (copy_size > LP_BUFFER_SIZE)
+		copy_size = LP_BUFFER_SIZE;
 
-#ifdef LP_STATS
-				lp->runchars = 0;
-#endif
+	if (copy_from_user (kbuf, buf, copy_size))
+		return -EFAULT;
 
-				if (lp_check_status(minor))
-				{
-					w_ctr(minor, LP_PSELECP | LP_PINITP);
-					return rc ? rc : -EIO;
-				}
+ 	/* Claim Parport or sleep until it becomes available
+ 	 */
+ 	lp_parport_claim (minor);
 
-				if (LP_POLLED(minor) ||
-				    lp_table[minor].irq_missed)
-				{
-				lp_polling:
-#if defined(LP_DEBUG) && defined(LP_STATS)
-					printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor));
-#endif
-					current->state = TASK_INTERRUPTIBLE;
-					lp_schedule(minor, LP_TIME(minor));
-				} else {
-					cli();
-					if (LP_PREEMPTED(minor))
-					{
-						/*
-						 * We can' t sleep on the interrupt
-						 * since another pardevice need the port.
-						 * We must check this in a cli() protected
-						 * envinroment to avoid parport sharing
-						 * starvation.
-						 */
-						sti();
-						goto lp_polling;
-					}
-					if (!lp_table[minor].irq_detected)
-						interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);
-					sti();
-				}
-			}
-		}
+	/* Go to compatibility mode. */
+	parport_negotiate (port, IEEE1284_MODE_COMPAT);
 
-		total_bytes_written += bytes_written;
-		buf += bytes_written;
-		count -= bytes_written;
+	do {
+		/* Wait until lp_read has finished. */
+		if (down_interruptible (&lp_table[minor].port_mutex))
+			break;
 
-	} while (count > 0);
+		/* Write the data. */
+		written = parport_write (port, kbuf, copy_size);
+		if (written >= 0) {
+			copy_size -= written;
+			count -= written;
+			buf  += written;
+			retv += written;
+		}
 
-	w_ctr(minor, LP_PSELECP | LP_PINITP);
-	return total_bytes_written;
-}
+		up (&lp_table[minor].port_mutex);
 
-static ssize_t lp_write(struct file * file, const char * buf,
-		        size_t count, loff_t *ppos)
-{
-	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
-	ssize_t retv;
+		if (signal_pending (current)) {
+			if (retv == 0)
+				retv = -EINTR;
 
-#ifdef LP_STATS
-	if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
-		lp_table[minor].runchars = 0;
+			break;
+		}
 
-	lp_table[minor].lastcall = jiffies;
-#endif
+		if (copy_size > 0) {
+			/* incomplete write -> check error ! */
+			int error = lp_check_status (minor);
 
- 	/* Claim Parport or sleep until it becomes available
- 	 */
- 	lp_parport_claim (minor);
+			if (LP_F(minor) & LP_ABORT) {
+				if (retv == 0)
+					retv = error;
+				break;
+			}
 
-	retv = lp_write_buf(minor, buf, count);
+			parport_yield_blocking (lp_table[minor].dev);
+		} else if (current->need_resched)
+			schedule ();
+
+		if (count) {
+			copy_size = count;
+			if (copy_size > LP_BUFFER_SIZE)
+				copy_size = LP_BUFFER_SIZE;
+
+			if (copy_from_user(kbuf, buf, copy_size)) {
+				if (retv == 0)
+					retv = -EFAULT;
+				break;
+			}
+		}	
+	} while (count > 0);
 
  	lp_parport_release (minor);
+
  	return retv;
 }
 
@@ -579,109 +400,54 @@
 	return -ESPIPE;
 }
 
-#ifdef CONFIG_PRINTER_READBACK
+#ifdef CONFIG_PARPORT_1284
 
-static int lp_read_nibble(int minor) 
-{
-	unsigned char i;
-	i = r_str(minor)>>3;
-	i &= ~8;
-	if ((i & 0x10) == 0) i |= 8;
-	return (i & 0x0f);
-}
-
-static void lp_read_terminate(struct parport *port) {
-	parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-	/* SelectIN high, AutoFeed low */
-	if (parport_wait_peripheral(port, 0x80, 0)) 
-		/* timeout, SelectIN high, Autofeed low */
-		return;
-	parport_write_control(port, parport_read_control(port) | 2);
-	/* AutoFeed high */
-	parport_wait_peripheral(port, 0x80, 0x80);
-	/* no timeout possible, Autofeed low, SelectIN high */
-	parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-}
-
-/* Status readback confirming to ieee1284 */
+/* Status readback conforming to ieee1284 */
 static ssize_t lp_read(struct file * file, char * buf,
-		       size_t length, loff_t *ppos)
+		       size_t count, loff_t *ppos)
 {
-	int i;
 	unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev);
-	char *temp = buf;
-	ssize_t count = 0;
-	unsigned char z = 0;
-	unsigned char Byte = 0;
 	struct parport *port = lp_table[minor].dev->port;
+	ssize_t retval = 0;
+	char *kbuf = lp_table[minor].lp_buffer;
+
+	if (count > LP_BUFFER_SIZE)
+		count = LP_BUFFER_SIZE;
 
 	lp_parport_claim (minor);
 
-	switch (parport_ieee1284_nibble_mode_ok(port, 0))
-	{
-	case 0:
-		/* Handshake failed. */
-		lp_read_terminate(port);
-		lp_parport_release (minor);
-		return -EIO;
-	case 1:
-		/* No data. */
-		lp_read_terminate(port);
-		lp_parport_release (minor);
-		return 0;
-	default:
-		/* Data available. */
+	if (!down_interruptible (&lp_table[minor].port_mutex)) {
+		for (;;) {
+			retval = parport_read (port, kbuf, count);
 
-		/* Hack: Wait 10ms (between events 6 and 7) */
-                schedule_timeout((HZ+99)/100);
-                break;
-	}
+			if (retval)
+				break;
 
-	for (i=0; ; i++) {
-		parport_frob_control(port, 2, 2); /* AutoFeed high */
-		if (parport_wait_peripheral(port, 0x40, 0)) {
-#ifdef LP_READ_DEBUG
-			/* Some peripherals just time out when they've sent
-			   all their data.  */
-			printk("%s: read1 timeout.\n", port->name);
-#endif
-			parport_frob_control(port, 2, 0); /* AutoFeed low */
-			break;
-		}
-		z = lp_read_nibble(minor);
-		parport_frob_control(port, 2, 0); /* AutoFeed low */
-		if (parport_wait_peripheral(port, 0x40, 0x40)) {
-			printk("%s: read2 timeout.\n", port->name);
-			break;
-		}
-		if ((i & 1) != 0) {
-			Byte |= (z<<4);
-			if (__put_user (Byte, temp))
-			{
-				count = -EFAULT;
+			if (file->f_flags & O_NONBLOCK)
 				break;
-			} else {
-				temp++;
 
-				if (++count == length)
-					break;
-			}
-			/* Does the error line indicate end of data? */
-			if ((parport_read_status(port) & LP_PERRORP) == 
-			    LP_PERRORP) 
+			/* Wait for an interrupt. */
+			interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+							LP_TIMEOUT_POLLED);
+
+			if (signal_pending (current)) {
+				retval = -EINTR;
 				break;
-		} else 
-			Byte=z;
-	}
+			}
+		}
 
-	lp_read_terminate(port);
+		up (&lp_table[minor].port_mutex);
+	}
 
 	lp_parport_release (minor);
 
-	return count;
+	if (retval > 0 && copy_to_user (buf, kbuf, retval))
+		retval = -EFAULT;
+
+	return retval;
 }
 
-#endif
+#endif /* IEEE 1284 support */
 
 static int lp_open(struct inode * inode, struct file * file)
 {
@@ -729,7 +495,6 @@
 		LP_F(minor) &= ~LP_BUSY;
 		return -ENOMEM;
 	}
-	init_waitqueue_head(&(lp_table[minor].wait_q));
 	return 0;
 }
 
@@ -752,7 +517,7 @@
 	int retval = 0;
 
 #ifdef LP_DEBUG
-	printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
+	printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
 #endif
 	if (minor >= LP_NO)
 		return -ENODEV;
@@ -785,12 +550,6 @@
 				LP_F(minor) &= ~LP_CAREFUL;
 			break;
 #endif
-		case LPTRUSTIRQ:
-			if (arg)
-				LP_F(minor) |= LP_TRUST_IRQ;
-			else
-				LP_F(minor) &= ~LP_TRUST_IRQ;
-			break;
 		case LPWAIT:
 			LP_WAIT(minor) = arg;
 			break;
@@ -834,16 +593,35 @@
 	return retval;
 }
 
+#ifdef CONFIG_PARPORT_1284
+static unsigned int lp_poll (struct file *filp, struct poll_table_struct *wait)
+{
+	unsigned int minor = MINOR (filp->f_dentry->d_inode->i_rdev);
+	unsigned int mask = POLLOUT | POLLWRNORM; /* always writable */
+
+	poll_wait (filp, &lp_table[minor].dataq, wait);
+
+	if (lp_table[minor].flags & LP_DATA_AVAIL)
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+#endif /* IEEE 1284 support */
+
 static struct file_operations lp_fops = {
 	lp_lseek,
-#ifdef CONFIG_PRINTER_READBACK
+#ifdef CONFIG_PARPORT_1284
 	lp_read,
 #else
 	NULL,
 #endif
 	lp_write,
 	NULL,		/* lp_readdir */
-	NULL,		/* lp_poll */
+#ifdef CONFIG_PARPORT_1284
+	lp_poll,
+#else
+	NULL,
+#endif
 	lp_ioctl,
 	NULL,		/* lp_mmap */
 	lp_open,
@@ -851,6 +629,70 @@
 	lp_release
 };
 
+/* --- support for console on the line printer ----------------- */
+
+#ifdef CONFIG_LP_CONSOLE
+
+#define CONSOLE_LP 0
+
+/* If the printer is out of paper, we can either lose the messages or
+ * stall until the printer is happy again.  Define CONSOLE_LP_STRICT
+ * non-zero to get the latter behaviour. */
+#define CONSOLE_LP_STRICT 1
+
+static void lp_console_write (struct console *co, const char *s,
+			      unsigned count)
+{
+	struct pardevice *dev = lp_table[CONSOLE_LP].dev;
+	struct parport *port = dev->port;
+	ssize_t written;
+	signed long old_to;
+
+	if (!(lp_table[CONSOLE_LP].flags & (1<<LP_HAVE_PORT_BIT))) {
+		if (parport_claim (dev))
+			/* Nothing we can do. */
+			return;
+		set_bit (LP_HAVE_PORT_BIT, &lp_table[CONSOLE_LP].flags);
+	}
+
+	old_to = parport_set_timeout (dev, 0);
+
+	/* Go to compatibility mode. */
+	parport_negotiate (port, IEEE1284_MODE_COMPAT);
+
+	do {
+		/* Write the data. */
+		written = parport_write (port, s, count);
+		if (written > 0) {
+			s += written;
+			count -= written;
+		}
+	} while (count > 0 && (CONSOLE_LP_STRICT || written > 0));
+
+	parport_set_timeout (dev, old_to);
+}
+
+static kdev_t lp_console_device (struct console *c)
+{
+	return MKDEV(LP_MAJOR, CONSOLE_LP);
+}
+
+static struct console lpcons = {
+	"lp",
+	lp_console_write,
+	NULL,
+	lp_console_device,
+	NULL,
+	NULL,
+	NULL,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+#endif /* console on line printer */
+
 /* --- initialisation code ------------------------------------- */
 
 #ifdef MODULE
@@ -864,8 +706,8 @@
 
 #else
 
-static int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
-static int reset __initdata = 0;
+static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int reset = 0;
 
 static int parport_ptr = 0;
 
@@ -896,10 +738,10 @@
 
 #endif
 
-int lp_register(int nr, struct parport *port)
+static int lp_register(int nr, struct parport *port)
 {
 	lp_table[nr].dev = parport_register_device(port, "lp", 
-						   lp_preempt, NULL,
+						   lp_preempt, lp_wakeup,
 						   lp_interrupt, 
 						   0,
 						   (void *) &lp_table[nr]);
@@ -916,13 +758,56 @@
 	return 0;
 }
 
-int lp_init(void)
+static void lp_attach (struct parport *port)
 {
-	unsigned int count = 0;
 	unsigned int i;
-	struct parport *port;
 
-	for(i = 0; i < LP_NO; i++) {
+	switch (parport_nr[0])
+	{
+	case LP_PARPORT_UNSPEC:
+	case LP_PARPORT_AUTO:
+		if (parport_nr[0] == LP_PARPORT_AUTO &&
+		    port->probe_info[0].class != PARPORT_CLASS_PRINTER)
+			return;
+
+		if (!lp_register(lp_count, port))
+			if (++lp_count == LP_NO)
+				break;
+
+		break;
+
+	default:
+		for (i = 0; i < LP_NO; i++) {
+			if (port->number == parport_nr[i]) {
+				if (!lp_register(i, port))
+					lp_count++;
+				break;
+			}
+		}
+		break;
+	}
+}
+
+static void lp_detach (struct parport *port)
+{
+	/* Write this some day. */
+}
+
+static struct parport_driver lp_driver = {
+	"lp",
+	lp_attach,
+	lp_detach,
+	NULL
+};
+
+int __init lp_init (void)
+{
+	int i;
+
+	if (parport_nr[0] == LP_PARPORT_OFF)
+		return 0;
+
+	for (i = 0; i < LP_NO; i++) {
 		lp_table[i].dev = NULL;
 		lp_table[i].flags = 0;
 		lp_table[i].chars = LP_INIT_CHAR;
@@ -932,55 +817,37 @@
 #ifdef LP_STATS
 		lp_table[i].lastcall = 0;
 		lp_table[i].runchars = 0;
-		memset(&lp_table[i].stats, 0, sizeof(struct lp_stats));
+		memset (&lp_table[i].stats, 0, sizeof (struct lp_stats));
 #endif
-		init_waitqueue_head(&lp_table[i].wait_q);
 		lp_table[i].last_error = 0;
-		lp_table[i].irq_detected = 0;
-		lp_table[i].irq_missed = 0;
+		init_waitqueue_head (&lp_table[i].waitq);
+		init_waitqueue_head (&lp_table[i].dataq);
+		init_MUTEX (&lp_table[i].port_mutex);
 	}
 
-	switch (parport_nr[0])
-	{
-	case LP_PARPORT_OFF:
-		return 0;
-
-	case LP_PARPORT_UNSPEC:
-	case LP_PARPORT_AUTO:
-	        for (port = parport_enumerate(); port; port = port->next) {
-
-			if (parport_nr[0] == LP_PARPORT_AUTO &&
-			    port->probe_info.class != PARPORT_CLASS_PRINTER)
-				continue;
-
-			if (!lp_register(count, port))
-				if (++count == LP_NO)
-					break;
-		}
-		break;
+	if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) {
+		printk ("lp: unable to get major %d\n", LP_MAJOR);
+		return -EIO;
+	}
 
-	default:
-		for (i = 0; i < LP_NO; i++) {
-			for (port = parport_enumerate(); port; 
-			     port = port->next) {
-				if (port->number == parport_nr[i]) {
-					if (!lp_register(i, port))
-						count++;
-					break;
-				}
-			}
-		}
-		break;
+	if (parport_register_driver (&lp_driver)) {
+		printk ("lp: unable to register with parport\n");
+		return -EIO;
 	}
 
-	if (count) {
-		if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) {
-			printk("lp: unable to get major %d\n", LP_MAJOR);
-			return -EIO;
-		}
-	} else {
-		printk(KERN_INFO "lp: driver loaded but no devices found\n");
+	if (!lp_count) {
+		printk (KERN_INFO "lp: driver loaded but no devices found\n");
+#ifndef CONFIG_PARPORT_12843
+		if (parport_nr[0] == LP_PARPORT_AUTO)
+			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;
 }
@@ -1018,10 +885,18 @@
 {
 	unsigned int offset;
 
+	parport_unregister_driver (&lp_driver);
+
+#ifdef CONFIG_LP_CONSOLE
+	unregister_console (&lpcons);
+#endif
+
 	unregister_chrdev(LP_MAJOR, "lp");
 	for (offset = 0; offset < LP_NO; offset++) {
 		if (lp_table[offset].dev == NULL)
 			continue;
+		if (lp_table[offset].flags & (1<<LP_HAVE_PORT_BIT))
+			parport_release (lp_table[offset].dev);
 		parport_unregister_device(lp_table[offset].dev);
 	}
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v2.3.9/linux/drivers/char/lp_intern.c	Thu Jul 30 11:17:12 1998
+++ linux/drivers/char/lp_intern.c	Mon Jul  5 20:35:18 1999
@@ -28,7 +28,6 @@
 #endif
 #ifdef CONFIG_ATARI
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 #endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- v2.3.9/linux/drivers/char/n_hdlc.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/char/n_hdlc.c	Mon Jul  5 20:35:18 1999
@@ -100,7 +100,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 #include <asm/system.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.3.9/linux/drivers/char/pc_keyb.c	Tue May 11 14:37:40 1999
+++ linux/drivers/char/pc_keyb.c	Mon Jul  5 20:35:18 1999
@@ -38,7 +38,6 @@
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/irq.h>
 
 /* Some configuration switches are present in the include file... */
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.3.9/linux/drivers/char/pcwd.c	Mon Aug 24 13:14:10 1998
+++ linux/drivers/char/pcwd.c	Tue Jul  6 19:05:48 1999
@@ -34,6 +34,9 @@
  * 971222       Changed open/close for temperature handling
  *              Michael Meskes <meskes@debian.org>.
  * 980112       Used minor numbers from include/linux/miscdevice.h
+ * 990605	Made changes to code to support Firmware 1.22a, added
+ *		fairly useless proc entry.
+ * 990610	removed said useless proc code for the merge <alan>
  */
 
 #include <linux/module.h>
@@ -55,6 +58,7 @@
 #include <linux/mm.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
+#include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -67,7 +71,7 @@
  */
 static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
 
-#define WD_VER                  "1.0 (11/18/96)"
+#define WD_VER                  "1.10 (06/05/99)"
 
 /*
  * It should be noted that PCWD_REVISION_B was removed because A and B
@@ -99,7 +103,7 @@
  * This routine checks the "current_readport" to see if the card lies there.
  * If it does, it returns accordingly.
  */
-__initfunc(static int pcwd_checkcard(void))
+static int __init pcwd_checkcard(void)
 {
 	int card_dat, prev_card_dat, found = 0, count = 0, done = 0;
 
@@ -228,10 +232,9 @@
 	int i, cdat, rv;
 	static struct watchdog_info ident=
 	{
-		/* FIXME: should set A/C here */
 		WDIOF_OVERHEAT|WDIOF_CARDRESET,
 		1,
-		"PCWD."
+		"PCWD"
 	};
 
 	switch(cmd) {
@@ -408,8 +411,11 @@
 	switch(MINOR(file->f_dentry->d_inode->i_rdev)) 
 	{
 		case TEMP_MINOR:
-		        /* c is in celsius, we need fahrenheit */
-		        cp = (c*9/5)+32;
+			/*
+			 * Convert metric to Fahrenheit, since this was
+			 * the decided 'standard' for this return value.
+			 */
+			cp = (c * 9 / 5) + 32;
 			if(copy_to_user(buf, &cp, 1))
 				return -EFAULT;
 			return 1;
@@ -450,7 +456,7 @@
 	return(PCWD_REVISION_C);
 }
 
-__initfunc(static int send_command(int cmd))
+static int __init send_command(int cmd)
 {
 	int i;
 
@@ -506,6 +512,38 @@
 	mode_debug = 0;
 }
 
+static int pcwd_proc_get_info(char *buffer, char **start, off_t offset,
+	int length, int inout)
+{
+	int len;
+	off_t begin = 0;
+	
+	revision = get_revision();
+	len = sprintf(buffer, "Version = " WD_VER "\n");
+	
+	if (revision == PCWD_REVISION_A)
+		len += sprintf(buffer + len, "Revision = A\n");
+	else
+		len += sprintf(buffer + len, "Revision = C\n");
+	
+	if (supports_temp) {
+		unsigned short c = inb(current_readport);
+		
+		len += sprintf(buffer + len, "Temp = Yes\n"
+			"Current temp = %d (Celsius)\n",
+			c);
+	} else
+		len += sprintf(buffer + len, "Temp = No\n");
+	
+	*start = buffer + (offset);
+	len -= offset;
+
+	if (len > length)
+		len = length;
+	
+	return len;
+}
+
 static struct file_operations pcwd_fops = {
 	NULL,		/* Seek */
 	pcwd_read,	/* Read */
@@ -539,14 +577,14 @@
 #ifdef	MODULE
 int init_module(void)
 #else
-__initfunc(int pcwatchdog_init(void))
+int __init pcwatchdog_init(void)
 #endif
 {
 	int i, found = 0;
 
 	revision = PCWD_REVISION_A;
 
-	printk("pcwd: v%s Ken Hollis (khollis@nurk.org)\n", WD_VER);
+	printk("pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
 
 	/* Initial variables */
 	is_open = 0;
@@ -588,6 +626,9 @@
 		printk("pcwd: Unable to get revision.\n");
 		return -1;
 	}
+
+	if (supports_temp)
+		printk("pcwd: Temperature Option Detected.\n");
 
 	debug_off();
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.9/linux/drivers/char/ppdev.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ppdev.c	Mon Jul  5 20:31:26 1999
@@ -0,0 +1,548 @@
+/*
+ * linux/drivers/char/ppdev.c
+ *
+ * This is the code behind /dev/parport* -- it allows a user-space
+ * application to use the parport subsystem.
+ *
+ * Copyright (C) 1998-9 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * 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.
+ *
+ * A /dev/parportxy device node represents an arbitrary device ('y')
+ * on port 'x'.  The following operations are possible:
+ *
+ * open		do nothing, set up default IEEE 1284 protocol to be COMPAT
+ * close	release port and unregister device (if necessary)
+ * ioctl
+ *   EXCL	register device exclusively (may fail)
+ *   CLAIM	(register device first time) parport_claim_or_block
+ *   RELEASE	parport_release
+ *   SETMODE	set the IEEE 1284 protocol to use for read/write
+ *   DATADIR	data_forward / data_reverse
+ *   WDATA	write_data
+ *   RDATA	read_data
+ *   WCONTROL	write_control
+ *   RCONTROL	read_control
+ *   FCONTROL	frob_control
+ *   RSTATUS	read_status
+ *   NEGOT	parport_negotiate
+ *   YIELD	parport_yield_blocking
+ * read/write	read or write in current IEEE 1284 protocol
+ * select	wait for interrupt (in readfds)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include "ppdev.h"
+
+#define PP_VERSION "ppdev: user-space parallel port driver"
+#define CHRDEV "ppdev"
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* The device minor encodes the parport number and (arbitrary) 
+ * pardevice number as (port << 4) | dev. */
+#define PP_PORT(minor) ((minor >> 4) & 0xf)
+#define PP_DEV(minor) ((minor) & 0xf)
+
+struct pp_struct {
+	struct pardevice * pdev;
+	wait_queue_head_t irq_wait;
+	int mode;
+	unsigned int flags;
+};
+
+/* pp_struct.flags bitfields */
+#define PP_CLAIMED    (1<<0)
+#define PP_EXCL       (1<<1)
+
+/* Other constants */
+#define PP_INTERRUPT_TIMEOUT (10 * HZ) /* 10s */
+#define PP_BUFFER_SIZE 256
+#define PARDEVICE_MAX 8
+
+static struct pp_struct pp_table[PARPORT_MAX][PARDEVICE_MAX];
+
+static loff_t pp_lseek (struct file * file, long long offset, int origin)
+{
+	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;
+
+	switch (pp->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:
+		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;
+
+	switch (pp->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:
+		fn = port->ops->epp_write_data;
+		break;
+
+	case IEEE1284_MODE_ECP:
+	case IEEE1284_MODE_ECPRLE:
+		fn = port->ops->ecp_write_data;
+		break;
+
+	case IEEE1284_MODE_ECPSWE:
+		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)
+{
+	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+	unsigned int portnum = PP_PORT (minor);
+	unsigned int dev = PP_DEV (minor);
+	char * kbuffer;
+	ssize_t bytes_read = 0;
+	ssize_t got = 0;
+
+	if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+		/* Don't have the port claimed */
+		printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+			minor);
+		return -EPERM;
+	}
+
+	kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
+	if (!kbuffer)
+		return -ENOMEM;
+
+	while (bytes_read < count) {
+		ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
+
+		got = do_read (&pp_table[portnum][dev], kbuffer, need);
+
+		if (got < 0) {
+			if (!bytes_read)
+				bytes_read = got;
+
+			break;
+		}
+
+		if (copy_to_user (kbuffer, buf + bytes_read, got)) {
+			bytes_read = -EFAULT;
+			break;
+		}
+
+		bytes_read += got;
+
+		if (signal_pending (current)) {
+			if (!bytes_read)
+				bytes_read = -EINTR;
+			break;
+		}
+
+		if (current->need_resched)
+			schedule ();
+	}
+
+	kfree (kbuffer);
+	return bytes_read;
+}
+
+static ssize_t pp_write (struct file * file, const char * buf, size_t count,
+			 loff_t * ppos)
+{
+	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+	unsigned int portnum = PP_PORT (minor);
+	unsigned int dev = PP_DEV (minor);
+	char * kbuffer;
+	ssize_t bytes_written = 0;
+	ssize_t wrote;
+
+	if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+		/* Don't have the port claimed */
+		printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+			minor);
+		return -EPERM;
+	}
+
+	kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
+	if (!kbuffer)
+		return -ENOMEM;
+
+	while (bytes_written < count) {
+		ssize_t n = min(count - bytes_written, PP_BUFFER_SIZE);
+
+		if (copy_from_user (kbuffer, buf + bytes_written, n)) {
+			bytes_written = -EFAULT;
+			break;
+		}
+
+		wrote = do_write (&pp_table[portnum][dev], kbuffer, n);
+
+		if (wrote < 0) {
+			if (!bytes_written)
+				bytes_written = wrote;
+			break;
+		}
+
+		bytes_written += wrote;
+
+		if (signal_pending (current)) {
+			if (!bytes_written)
+				bytes_written = -EINTR;
+			break;
+		}
+
+		if (current->need_resched)
+			schedule ();
+	}
+
+	kfree (kbuffer);
+	return bytes_written;
+}
+
+static void pp_irq (int irq, void * private, struct pt_regs * unused)
+{
+	struct pp_struct * pp = (struct pp_struct *) private;
+	wake_up_interruptible (&pp->irq_wait);
+}
+
+static int register_device (int minor)
+{
+	unsigned int portnum = PP_PORT (minor);
+	unsigned int dev = PP_DEV (minor);
+	struct parport * port;
+	struct pardevice * pdev = NULL;
+	char *name;
+	int fl;
+
+	name = kmalloc (strlen (CHRDEV) + 3, GFP_KERNEL);
+	if (name == NULL)
+		return -ENOMEM;
+
+	sprintf (name, CHRDEV "%02x", minor);
+	port = parport_enumerate (); /* FIXME: use attach/detach */
+
+	while (port && port->number != portnum)
+		port = port->next;
+
+	if (!port) {
+		printk (KERN_WARNING "%s: no associated port!\n", name);
+		kfree (name);
+		return -ENXIO;
+	}
+
+	fl = (pp_table[portnum][dev].flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+	pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
+					&pp_table[portnum][dev]);
+
+	if (!pdev) {
+		printk (KERN_WARNING "%s: failed to register device!\n", name);
+		kfree (name);
+		return -ENXIO;
+	}
+
+	pp_table[portnum][dev].pdev = pdev;
+	printk (KERN_DEBUG "%s: registered pardevice\n", name);
+	return 0;
+}
+
+static int pp_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int portnum = PP_PORT (minor);
+	unsigned int dev = PP_DEV (minor);
+	struct parport * port;
+
+	/* First handle the cases that don't take arguments. */
+	if (cmd == PPCLAIM) {
+		if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+			printk (KERN_DEBUG CHRDEV
+				"%02x: you've already got it!\n", minor);
+			return -EINVAL;
+		}
+
+		/* Deferred device registration. */
+		if (!pp_table[portnum][dev].pdev) {
+			int err = register_device (minor);
+			if (err)
+				return err;
+		}
+
+		parport_claim_or_block (pp_table[portnum][dev].pdev);
+		pp_table[portnum][dev].flags |= PP_CLAIMED;
+		return 0;
+	}
+
+	port = pp_table[portnum][dev].pdev->port;
+	if (cmd == PPEXCL) {
+		if (pp_table[portnum][dev].pdev) {
+			printk (KERN_DEBUG CHRDEV "%02x: too late for PPEXCL; "
+				"already registered\n", minor);
+			if (pp_table[portnum][dev].flags & PP_EXCL)
+				/* But it's not really an error. */
+				return 0;
+			/* There's no chance of making the driver happy. */
+			return -EINVAL;
+		}
+
+		/* Just remember to register the device exclusively
+		 * when we finally do the registration. */
+		pp_table[portnum][dev].flags |= PP_EXCL;
+		return 0;
+	}
+
+	/* Everything else requires the port to be claimed, so check
+	 * that now. */
+	if ((pp_table[portnum][dev].flags & PP_CLAIMED) == 0) {
+		printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+			minor);
+		return -EPERM;
+	}
+
+	switch (cmd) {
+		unsigned char reg;
+		unsigned char mask;
+		int mode;
+
+	case PPRSTATUS:
+		reg = parport_read_status (port);
+		return copy_to_user ((unsigned char *) arg, &reg,
+				     sizeof (reg));
+
+	case PPRDATA:
+		reg = parport_read_data (port);
+		return copy_to_user ((unsigned char *) arg, &reg,
+				     sizeof (reg));
+
+	case PPRCONTROL:
+		reg = parport_read_control (port);
+		return copy_to_user ((unsigned char *) arg, &reg,
+				     sizeof (reg));
+
+	case PPYIELD:
+		parport_yield_blocking (pp_table[portnum][dev].pdev);
+		return 0;
+
+	case PPRELEASE:
+		parport_release (pp_table[portnum][dev].pdev);
+		pp_table[portnum][dev].flags &= ~PP_CLAIMED;
+		return 0;
+
+	case PPSETMODE:
+		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+			return -EFAULT;
+		/* FIXME: validate mode */
+		pp_table[portnum][dev].mode = mode;
+		return 0;
+
+	case PPWCONTROL:
+		if (copy_from_user (&reg, (unsigned char *) arg, sizeof (reg)))
+			return -EFAULT;
+		parport_write_control (port, reg);
+		return 0;
+
+	case PPWDATA:
+		if (copy_from_user (&reg, (unsigned char *) arg, sizeof (reg)))
+			return -EFAULT;
+		parport_write_data (port, reg);
+		return 0;
+
+	case PPFCONTROL:
+		if (copy_from_user (&mask, (unsigned char *) arg,
+				    sizeof (mask)))
+			return -EFAULT;
+		if (copy_from_user (&reg, 1 + (unsigned char *) arg,
+				    sizeof (reg)))
+			return -EFAULT;
+		parport_frob_control (port, mask, reg);
+		return 0;
+
+	case PPDATADIR:
+		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+			return -EFAULT;
+		if (mode)
+			port->ops->data_reverse (port);
+		else
+			port->ops->data_forward (port);
+		return 0;
+
+	case PPNEGOT:
+		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+			return -EFAULT;
+		/* FIXME: validate mode */
+		return parport_negotiate (port, mode);
+
+	default:
+		printk (KERN_DEBUG CHRDEV "%02x: What? (cmd=0x%x\n", minor,
+			cmd);
+		return -EINVAL;
+	}
+
+	/* Keep the compiler happy */
+	return 0;
+}
+
+static int pp_open (struct inode * inode, struct file * file)
+{
+	unsigned int minor = MINOR (inode->i_rdev);
+	unsigned int portnum = PP_PORT (minor);
+	unsigned int dev = PP_DEV (minor);
+
+	if (portnum >= PARPORT_MAX)
+		return -ENXIO;
+
+	if (pp_table[portnum][dev].pdev)
+		return -EBUSY;
+
+	pp_table[portnum][dev].mode = IEEE1284_MODE_COMPAT;
+	pp_table[portnum][dev].flags = 0;
+	init_waitqueue_head (&pp_table[portnum][dev].irq_wait);
+
+	/* Defer the actual device registration until the first claim.
+	 * That way, we know whether or not the driver wants to have
+	 * exclusive access to the port (PPEXCL).
+	 */
+	pp_table[portnum][dev].pdev = NULL;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int pp_release (struct inode * inode, struct file * file)
+{
+	unsigned int minor = MINOR (inode->i_rdev);
+	unsigned int portnum = PP_PORT (minor);
+	unsigned int dev = PP_DEV (minor);
+
+	if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+		parport_release (pp_table[portnum][dev].pdev);
+		printk (KERN_DEBUG CHRDEV "%02x: released pardevice because "
+			"user-space forgot\n", minor);
+	}
+
+	if (pp_table[portnum][dev].pdev) {
+		kfree (pp_table[portnum][dev].pdev->name);
+		parport_unregister_device (pp_table[portnum][dev].pdev);
+		pp_table[portnum][dev].pdev = NULL;
+		printk (KERN_DEBUG CHRDEV "%02x: unregistered pardevice\n",
+			minor);
+	}
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#if 0
+static unsigned int pp_poll (struct file * file, poll_table * wait)
+{
+	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+	poll_wait (file, &pp_table[minor].irq_wait, wait);
+	return 0; /* FIXME! Return value is wrong here */
+}
+#endif
+
+static struct file_operations pp_fops = {
+	pp_lseek,
+	pp_read,
+	pp_write,
+	NULL,	/* pp_readdir */
+	NULL,   /* pp_poll */
+	pp_ioctl,
+	NULL,	/* pp_mmap */
+	pp_open,
+	NULL,   /* pp_flush */
+	pp_release
+};
+
+#ifdef MODULE
+#define pp_init init_module
+#endif
+
+int pp_init (void)
+{
+	if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
+		printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
+			PP_MAJOR);
+		return -EIO;
+	}
+
+	printk (KERN_INFO PP_VERSION "\n");
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module (void)
+{
+	/* Clean up all parport stuff */
+	unregister_chrdev (PP_MAJOR, CHRDEV);
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.9/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h
--- v2.3.9/linux/drivers/char/ppdev.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ppdev.h	Mon Jul  5 20:31:26 1999
@@ -0,0 +1,65 @@
+/*
+ * linux/drivers/char/ppdev.h
+ *
+ * User-space parallel port device driver (header file).
+ *
+ * Copyright (C) 1998-9 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * 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.
+ *
+ */
+
+#define PP_MAJOR	99
+
+#define PP_IOCTL	'p'
+
+/* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */
+#define PPSETMODE	_IOW(PP_IOCTL, 0x80, int)
+
+/* Read status */
+#define PPRSTATUS	_IOR(PP_IOCTL, 0x81, unsigned char)
+#define PPWSTATUS	OBSOLETE__IOW(PP_IOCTL, 0x82, unsigned char)
+
+/* Read/write control */
+#define PPRCONTROL	_IOR(PP_IOCTL, 0x83, unsigned char)
+#define PPWCONTROL	_IOW(PP_IOCTL, 0x84, unsigned char)
+
+struct ppdev_frob_struct {
+	unsigned char mask;
+	unsigned char val;
+};
+#define PPFCONTROL      _IOW(PP_IOCTL, 0x8e, struct ppdev_frob_struct)
+
+/* Read/write data */
+#define PPRDATA		_IOR(PP_IOCTL, 0x85, unsigned char)
+#define PPWDATA		_IOW(PP_IOCTL, 0x86, unsigned char)
+
+/* Read/write econtrol (not used) */
+#define PPRECONTROL	OBSOLETE__IOR(PP_IOCTL, 0x87, unsigned char)
+#define PPWECONTROL	OBSOLETE__IOW(PP_IOCTL, 0x88, unsigned char)
+
+/* Read/write FIFO (not used) */
+#define PPRFIFO		OBSOLETE__IOR(PP_IOCTL, 0x89, unsigned char)
+#define PPWFIFO		OBSOLETE__IOW(PP_IOCTL, 0x8a, unsigned char)
+
+/* Claim the port to start using it */
+#define PPCLAIM		_IO(PP_IOCTL, 0x8b)
+
+/* Release the port when you aren't using it */
+#define PPRELEASE	_IO(PP_IOCTL, 0x8c)
+
+/* Yield the port (release it if another driver is waiting,
+ * then reclaim) */
+#define PPYIELD		_IO(PP_IOCTL, 0x8d)
+
+/* Register device exclusively (must be before PPCLAIM). */
+#define PPEXCL		_IO(PP_IOCTL, 0x8f)
+
+/* Data line direction: non-zero for input mode. */
+#define PPDATADIR	_IOW(PP_IOCTL, 0x90, int)
+
+/* Negotiate a particular IEEE 1284 mode. */
+#define PPNEGOT		_IOW(PP_IOCTL, 0x91, int)
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-aimslab.c linux/drivers/char/radio-aimslab.c
--- v2.3.9/linux/drivers/char/radio-aimslab.c	Thu Apr 15 05:42:40 1999
+++ linux/drivers/char/radio-aimslab.c	Mon Jul  5 20:07:02 1999
@@ -324,7 +324,7 @@
 	NULL
 };
 
-__initfunc(int rtrack_init(struct video_init *v))
+int __init rtrack_init(struct video_init *v)
 {
 	if (check_region(io, 2)) 
 	{
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-aztech.c linux/drivers/char/radio-aztech.c
--- v2.3.9/linux/drivers/char/radio-aztech.c	Thu Apr 15 05:42:40 1999
+++ linux/drivers/char/radio-aztech.c	Mon Jul  5 20:07:02 1999
@@ -279,7 +279,7 @@
 	NULL
 };
 
-__initfunc(int aztech_init(struct video_init *v))
+int __init aztech_init(struct video_init *v)
 {
 	if (check_region(io, 2)) 
 	{
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c
--- v2.3.9/linux/drivers/char/radio-cadet.c	Mon Jun  7 16:17:59 1999
+++ linux/drivers/char/radio-cadet.c	Mon Jul  5 20:07:02 1999
@@ -1,7 +1,7 @@
-/* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
+/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
  *
  * by Fred Gleason <fredg@wava.com>
- * Version 0.3.2
+ * Version 0.3.3
  *
  * (Loosely) based on code for the Aztech radio card by
  *
@@ -346,17 +346,13 @@
 static long cadet_read(struct video_device *v,char *buf,unsigned long count,
 		       int nonblock)
 {
-        int i=0,c;
+        int i=0;
 	unsigned char readbuf[RDS_BUFFER];
 
         if(rdsstat==0) {
 	        cadet_lock++;
 	        rdsstat=1;
 		outb(0x80,io);        /* Select RDS fifo */
-		c=3*(inb(io)&0x03);
-		for(i=0;i<c;i++) {    /* Flush the fifo */
-		        inb(io+1);
-		}
 		cadet_lock--;
 		init_timer(&readtimer);
 		readtimer.function=cadet_handler;
@@ -546,7 +542,7 @@
 	NULL
 };
 
-__initfunc(int cadet_init(struct video_init *v))
+int __init cadet_init(struct video_init *v)
 {
 #ifndef MODULE        
         if(cadet_probe()<0) {
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-gemtek.c linux/drivers/char/radio-gemtek.c
--- v2.3.9/linux/drivers/char/radio-gemtek.c	Thu Apr 15 05:42:40 1999
+++ linux/drivers/char/radio-gemtek.c	Mon Jul  5 20:07:02 1999
@@ -250,7 +250,7 @@
 	NULL
 };
 
-__initfunc(int gemtek_init(struct video_init *v))
+int __init gemtek_init(struct video_init *v)
 {
 	if (check_region(io, 4)) 
 	{
@@ -282,7 +282,7 @@
 MODULE_AUTHOR("Jonas Munsin");
 MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
 MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c)");
+MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (or 0x248 for the combined sound/radiocard))");
 
 EXPORT_NO_SYMBOLS;
 
@@ -290,7 +290,7 @@
 {
 	if(io==-1)
 	{
-		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c\n");
+		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (or io=0x248 for the combined sound/radiocard)\n");
 		return -EINVAL;
 	}
 	return gemtek_init(NULL);
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-miropcm20.c linux/drivers/char/radio-miropcm20.c
--- v2.3.9/linux/drivers/char/radio-miropcm20.c	Thu Apr 15 05:42:40 1999
+++ linux/drivers/char/radio-miropcm20.c	Mon Jul  5 20:07:02 1999
@@ -205,7 +205,7 @@
 	NULL
 };
 
-__initfunc(int pcm20_init(struct video_init *v))
+int __init pcm20_init(struct video_init *v)
 {
 
 	pcm20_radio.priv=&pcm20_unit;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-rtrack2.c linux/drivers/char/radio-rtrack2.c
--- v2.3.9/linux/drivers/char/radio-rtrack2.c	Thu Apr 15 05:42:40 1999
+++ linux/drivers/char/radio-rtrack2.c	Mon Jul  5 20:07:02 1999
@@ -218,7 +218,7 @@
 	NULL
 };
 
-__initfunc(int rtrack2_init(struct video_init *v))
+int __init rtrack2_init(struct video_init *v)
 {
 	if (check_region(io, 4)) 
 	{
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-sf16fmi.c linux/drivers/char/radio-sf16fmi.c
--- v2.3.9/linux/drivers/char/radio-sf16fmi.c	Sat Apr 24 17:49:37 1999
+++ linux/drivers/char/radio-sf16fmi.c	Mon Jul  5 20:07:02 1999
@@ -276,7 +276,7 @@
 	NULL
 };
 
-__initfunc(int fmi_init(struct video_init *v))
+int __init fmi_init(struct video_init *v)
 {
 	if (check_region(io, 2)) 
 	{
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-terratec.c linux/drivers/char/radio-terratec.c
--- v2.3.9/linux/drivers/char/radio-terratec.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/radio-terratec.c	Mon Jul  5 20:07:02 1999
@@ -0,0 +1,353 @@
+/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support
+ * (c) 1999 R. Offermanns (rolf@offermanns.de)
+ * based on the aimslab radio driver from M. Kirkwood
+ * many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
+ * 
+ *
+ * History:
+ * 1999-05-21	First preview release
+ * 
+ *  Notes on the hardware:
+ *  There are two "main" chips on the card:
+ *  - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
+ *  - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf)
+ *  (you can get the datasheet at the above links)
+ *
+ *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *  Volume Control is done digitally
+ *
+ *  there is a I2C controlled RDS decoder (SAA6588)  onboard, which i would like to support someday
+ *  (as soon i have understand how to get started :)
+ *  If you can help me out with that, please contact me!!
+ *
+ *  
+ */
+
+#include <linux/module.h>	/* Modules 			*/
+#include <linux/init.h>		/* Initdata			*/
+#include <linux/ioport.h>	/* check_region, request_region	*/
+#include <linux/delay.h>	/* udelay			*/
+#include <asm/io.h>		/* outb, outb_p			*/
+#include <asm/uaccess.h>	/* copy to/from user		*/
+#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/config.h>	/* CONFIG_RADIO_TERRATEC_PORT 	*/
+
+#ifndef CONFIG_RADIO_TERRATEC_PORT
+#define CONFIG_RADIO_TERRATEC_PORT 0x590
+#endif
+
+/**************** this ones are for the terratec *******************/
+#define BASEPORT 	0x590
+#define VOLPORT 	0x591
+#define WRT_DIS 	0x00
+#define CLK_OFF		0x00
+#define IIC_DATA	0x01
+#define IIC_CLK		0x02
+#define DATA		0x04
+#define CLK_ON 		0x08
+#define WRT_EN		0x10
+/*******************************************************************/
+
+static int io = CONFIG_RADIO_TERRATEC_PORT; 
+static int users = 0;
+
+struct tt_device
+{
+	int port;
+	int curvol;
+	unsigned long curfreq;
+	int muted;
+};
+
+
+/* local things */
+
+static void cardWriteVol(int volume)
+{
+	int i;
+	volume = volume+(volume * 32); // change both channels
+	for (i=0;i<8;i++)
+	{
+		if (volume & (0x80>>i))
+			outb(0x80, VOLPORT);
+		else outb(0x00, VOLPORT);
+	}
+}
+
+
+
+static void tt_mute(struct tt_device *dev)
+{
+	dev->muted = 1;
+	cardWriteVol(0);
+}
+
+static int tt_setvol(struct tt_device *dev, int vol)
+{
+	
+//	printk(KERN_ERR "setvol called, vol = %d\n", vol);
+
+	if(vol == dev->curvol) {	/* requested volume = current */
+		if (dev->muted) {	/* user is unmuting the card  */
+			dev->muted = 0;
+			cardWriteVol(vol);	/* enable card */
+		}	
+	
+		return 0;
+	}
+
+	if(vol == 0) {			/* volume = 0 means mute the card */
+		cardWriteVol(0);	/* "turn off card" by setting vol to 0 */
+		dev->curvol = vol;	/* track the volume state!	*/
+		return 0;
+	}
+
+	dev->muted = 0;
+	
+	cardWriteVol(vol);
+	 
+	dev->curvol = vol;
+
+	return 0;
+
+}
+
+
+/* this is the worst part in this driver */
+/* many more or less strange things are going on here, but hey, it works :) */
+
+static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
+{	
+	int freq;
+	int i;
+	int p;
+	int  temp;
+	long rest;
+     
+	unsigned char buffer[25];		/* we have to bit shift 25 registers */
+	freq = freq1/160;			/* convert the freq. to a nice to handel value */
+	for(i=24;i>-1;i--)
+		buffer[i]=0;
+
+	rest = freq*10+10700;		/* i once had understood what is going on here */
+					/* maybe some wise guy (friedhelm?) can comment this stuff */
+	i=13;
+	p=10;
+	temp=102400;
+	while (rest!=0)
+	{
+		if (rest%temp  == rest)
+			buffer[i] = 0;
+		else 
+		{
+			buffer[i] = 1; 
+			rest = rest-temp;
+		}
+		i--;
+		p--;
+		temp = temp/2;
+       }
+
+	for (i=24;i>-1;i--)			/* bit shift the values to the radiocard */
+	{
+		if (buffer[i]==1) 
+		{
+			outb(WRT_EN|DATA, BASEPORT);
+			outb(WRT_EN|DATA|CLK_ON  , BASEPORT);
+			outb(WRT_EN|DATA, BASEPORT);
+		}
+		else
+		{
+			outb(WRT_EN|0x00, BASEPORT);
+			outb(WRT_EN|0x00|CLK_ON  , BASEPORT);
+		}
+	}
+	outb(0x00, BASEPORT);     
+  
+  	return 0;
+}
+
+int tt_getsigstr(struct tt_device *dev)		/* TODO */
+{
+	if (inb(io) & 2)	/* bit set = no signal present	*/
+		return 0;
+	return 1;		/* signal present		*/
+}
+
+
+/* implement the video4linux api */
+
+static int tt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct tt_device *tt=dev->priv;
+	
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability v;
+			v.type=VID_TYPE_TUNER;
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			strcpy(v.name, "ActiveRadio");
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg,sizeof(v))!=0) 
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */ 
+				return -EINVAL;
+			v.rangelow=(87*16000);
+			v.rangehigh=(108*16000);
+			v.flags=VIDEO_TUNER_LOW;
+			v.mode=VIDEO_MODE_AUTO;
+			strcpy(v.name, "FM");
+			v.signal=0xFFFF*tt_getsigstr(tt);
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			/* Only 1 tuner so no setting needed ! */
+			return 0;
+		}
+		case VIDIOCGFREQ:
+			if(copy_to_user(arg, &tt->curfreq, sizeof(tt->curfreq)))
+				return -EFAULT;
+			return 0;
+		case VIDIOCSFREQ:
+			if(copy_from_user(&tt->curfreq, arg,sizeof(tt->curfreq)))
+				return -EFAULT;
+			tt_setfreq(tt, tt->curfreq);
+			return 0;
+		case VIDIOCGAUDIO:
+		{	
+			struct video_audio v;
+			memset(&v,0, sizeof(v));
+			v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+			v.volume=tt->curvol * 6554;
+			v.step=6554;
+			strcpy(v.name, "Radio");
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v))) 
+				return -EFAULT;	
+			if(v.audio) 
+				return -EINVAL;
+
+			if(v.flags&VIDEO_AUDIO_MUTE) 
+				tt_mute(tt);
+			else
+				tt_setvol(tt,v.volume/6554);	
+
+			return 0;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int tt_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void tt_close(struct video_device *dev)
+{
+	users--;
+	MOD_DEC_USE_COUNT;
+}
+
+static struct tt_device terratec_unit;
+
+static struct video_device terratec_radio=
+{
+	"TerraTec ActiveRadio",
+	VID_TYPE_TUNER,
+	VID_HARDWARE_TERRATEC,
+	tt_open,
+	tt_close,
+	NULL,	/* Can't read  (no capture ability) */
+	NULL,	/* Can't write */
+	NULL,	/* No poll */
+	tt_ioctl,
+	NULL,
+	NULL
+};
+
+__initfunc(int terratec_init(struct video_init *v))
+{
+	if (check_region(io, 2)) 
+	{
+		printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
+		return -EBUSY;
+	}
+
+	terratec_radio.priv=&terratec_unit;
+	
+	if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1)
+		return -EINVAL;
+		
+	request_region(io, 2, "terratec");
+	printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
+
+ 	/* mute card - prevents noisy bootups */
+
+	/* this ensures that the volume is all the way down  */
+	cardWriteVol(0);
+	terratec_unit.curvol = 0;
+
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("R.OFFERMANNS & others");
+MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+	if(io==-1)
+	{
+		printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+		return -EINVAL;
+	}
+	return terratec_init(NULL);
+}
+
+void cleanup_module(void)
+{
+	video_unregister_device(&terratec_radio);
+	release_region(io,2);
+	printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");	
+}
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-zoltrix.c linux/drivers/char/radio-zoltrix.c
--- v2.3.9/linux/drivers/char/radio-zoltrix.c	Mon May 10 13:00:10 1999
+++ linux/drivers/char/radio-zoltrix.c	Mon Jul  5 20:07:02 1999
@@ -333,7 +333,7 @@
 	NULL
 };
 
-__initfunc(int zoltrix_init(struct video_init *v))
+int __init zoltrix_init(struct video_init *v)
 {
 	if (check_region(io, 2)) {
 		printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
diff -u --recursive --new-file v2.3.9/linux/drivers/char/rocket.c linux/drivers/char/rocket.c
--- v2.3.9/linux/drivers/char/rocket.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/rocket.c	Mon Jul  5 20:35:18 1999
@@ -57,14 +57,13 @@
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
 #endif
-#include <linux/module.h>
 #else /* !NEW_MODULES */
 #ifdef MODVERSIONS
 #define MODULE
 #endif
-#include <linux/module.h>
 #endif /* NEW_MODULES */
 
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/major.h>
 #include <linux/kernel.h>
@@ -154,7 +153,6 @@
 /*
  * NB. we must include the kernel idenfication string in to install the module.
  */
-#include <linux/version.h>
 /*static*/ char kernel_version[] = UTS_RELEASE;
 #endif
 
@@ -1664,7 +1662,6 @@
 		       jiffies, check_time);
 #endif
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(check_time);
 		if (signal_pending(current))
 			break;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/saa7111.c linux/drivers/char/saa7111.c
--- v2.3.9/linux/drivers/char/saa7111.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/saa7111.c	Mon Jul  5 20:07:02 1999
@@ -0,0 +1,421 @@
+/* 
+   saa7111 - Philips SAA7111A video decoder driver version 0.0.3
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.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 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/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define DEBUG(x)		/* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct saa7111 {
+	struct i2c_bus *bus;
+	int addr;
+	unsigned char reg[32];
+
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+#define   I2C_SAA7111        0x48
+
+#define   I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data)
+{
+	int ack;
+	unsigned long flags;
+
+	LOCK_I2C_BUS(dev->bus);
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+	dev->reg[subaddr] = data;
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return ack;
+}
+
+static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len)
+{
+	int ack;
+	unsigned subaddr;
+	unsigned long flags;
+
+	while (len > 1) {
+		LOCK_I2C_BUS(dev->bus);
+		i2c_start(dev->bus);
+		i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+		len -= 2;
+		while (len > 1 && *data == ++subaddr) {
+			data++;
+			ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+			len -= 2;
+		}
+		i2c_stop(dev->bus);
+		UNLOCK_I2C_BUS(dev->bus);
+	}
+	return ack;
+}
+
+static int saa7111_read(struct saa7111 *dev, unsigned char subaddr)
+{
+	int data;
+	unsigned long flags;
+
+	LOCK_I2C_BUS(dev->bus);
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY);
+	data = i2c_readbyte(dev->bus, 1);
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return data;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7111_attach(struct i2c_device *device)
+{
+	int i;
+	struct saa7111 *decoder;
+
+	static const unsigned char init[] =
+	{
+		0x00, 0x00,	/* 00 - ID byte */
+		0x01, 0x00,	/* 01 - reserved */
+
+	/*front end */
+		0x02, 0xd0,	/* 02 - FUSE=3, GUDL=2, MODE=0 */
+		0x03, 0x23,	/* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
+		0x04, 0x00,	/* 04 - GAI1=256 */
+		0x05, 0x00,	/* 05 - GAI2=256 */
+
+	/* decoder */
+		0x06, 0xf6,	/* 06 - HSB at  13(50Hz) /  17(60Hz) pixels after end of last line */
+		0x07, 0xdd,	/* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */
+		0x08, 0xc8,	/* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */
+		0x09, 0x01,	/* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */
+		0x0a, 0x80,	/* 0a - BRIG=128 */
+		0x0b, 0x47,	/* 0b - CONT=1.109 */
+		0x0c, 0x40,	/* 0c - SATN=1.0 */
+		0x0d, 0x00,	/* 0d - HUE=0 */
+		0x0e, 0x01,	/* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
+		0x0f, 0x00,	/* 0f - reserved */
+		0x10, 0x48,	/* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
+		0x11, 0x1c,	/* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+		0x12, 0x00,	/* 12 - output control 2 */
+		0x13, 0x00,	/* 13 - output control 3 */
+		0x14, 0x00,	/* 14 - reserved */
+		0x15, 0x00,	/* 15 - VBI */
+		0x16, 0x00,	/* 16 - VBI */
+		0x17, 0x00,	/* 17 - VBI */
+	};
+
+	device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL);
+	if (decoder == NULL) {
+		return -ENOMEM;
+	}
+	MOD_INC_USE_COUNT;
+
+	memset(decoder, 0, sizeof(struct saa7111));
+	strcpy(device->name, "saa7111");
+	decoder->bus = device->bus;
+	decoder->addr = device->addr;
+	decoder->norm = VIDEO_MODE_NTSC;
+	decoder->input = 0;
+	decoder->enable = 1;
+	decoder->bright = 32768;
+	decoder->contrast = 32768;
+	decoder->hue = 32768;
+	decoder->sat = 32768;
+
+	i = saa7111_write_block(decoder, init, sizeof(init));
+	if (i < 0) {
+		printk(KERN_ERR "%s_attach: init status %d\n", device->name, i);
+	} else {
+		printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00));
+	}
+	return 0;
+}
+
+
+static int saa7111_detach(struct i2c_device *device)
+{
+	kfree(device->data);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg)
+{
+	struct saa7111 *decoder = device->data;
+
+	switch (cmd) {
+
+#if defined(DECODER_DUMP)
+	case DECODER_DUMP:
+		{
+			int i;
+
+			for (i = 0; i < 32; i += 16) {
+				int j;
+
+				printk("KERN_DEBUG %s: %03x", device->name, i);
+				for (j = 0; j < 16; ++j) {
+					printk(" %02x", saa7111_read(decoder, i + j));
+				}
+				printk("\n");
+			}
+		}
+		break;
+#endif				/* defined(DECODER_DUMP) */
+
+	case DECODER_GET_CAPABILITIES:
+		{
+			struct video_decoder_capability *cap = arg;
+
+			cap->flags
+			    = VIDEO_DECODER_PAL
+			    | VIDEO_DECODER_NTSC
+			    | VIDEO_DECODER_AUTO
+			    | VIDEO_DECODER_CCIR;
+			cap->inputs = 8;
+			cap->outputs = 1;
+		}
+		break;
+
+	case DECODER_GET_STATUS:
+		{
+			int *iarg = arg;
+			int status;
+			int res;
+
+			status = saa7111_read(decoder, 0x1f);
+			res = 0;
+			if ((status & (1 << 6)) == 0) {
+				res |= DECODER_STATUS_GOOD;
+			}
+			switch (decoder->norm) {
+			case VIDEO_MODE_NTSC:
+				res |= DECODER_STATUS_NTSC;
+				break;
+			case VIDEO_MODE_PAL:
+				res |= DECODER_STATUS_PAL;
+				break;
+			default:
+			case VIDEO_MODE_AUTO:
+				if ((status & (1 << 5)) != 0) {
+					res |= DECODER_STATUS_NTSC;
+				} else {
+					res |= DECODER_STATUS_PAL;
+				}
+				break;
+			}
+			if ((status & (1 << 0)) != 0) {
+				res |= DECODER_STATUS_COLOR;
+			}
+			*iarg = res;
+		}
+		break;
+
+	case DECODER_SET_NORM:
+		{
+			int *iarg = arg;
+
+			switch (*iarg) {
+
+			case VIDEO_MODE_NTSC:
+				saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40);
+				break;
+
+			case VIDEO_MODE_PAL:
+				saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00);
+				break;
+
+			case VIDEO_MODE_AUTO:
+				saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80);
+				break;
+
+			default:
+				return -EINVAL;
+
+			}
+			decoder->norm = *iarg;
+		}
+		break;
+
+	case DECODER_SET_INPUT:
+		{
+			int *iarg = arg;
+
+			if (*iarg < 0 || *iarg > 7) {
+				return -EINVAL;
+			}
+			if (decoder->input != *iarg) {
+				decoder->input = *iarg;
+				/* select mode */
+				saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);
+				/* bypass chrominance trap for modes 4..7 */
+				saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+			}
+		}
+		break;
+
+	case DECODER_SET_OUTPUT:
+		{
+			int *iarg = arg;
+
+			/* not much choice of outputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+		}
+		break;
+
+	case DECODER_ENABLE_OUTPUT:
+		{
+			int *iarg = arg;
+			int enable = (*iarg != 0);
+
+			if (decoder->enable != enable) {
+				decoder->enable = enable;
+
+// RJ: If output should be disabled (for playing videos), we also need a open PLL.
+				//     The input is set to 0 (where no input source is connected), although this
+				//     is not necessary.
+				//
+				//     If output should be enabled, we have to reverse the above.
+
+				if (decoder->enable) {
+					saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);
+					saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb));
+					saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c);
+				} else {
+					saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8));
+					saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04);
+					saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3));
+				}
+			}
+		}
+		break;
+
+	case DECODER_SET_PICTURE:
+		{
+			struct video_picture *pic = arg;
+
+			if (decoder->bright != pic->brightness) {
+				/* We want 0 to 255 we get 0-65535 */
+				decoder->bright = pic->brightness;
+				saa7111_write(decoder, 0x0a, decoder->bright >> 8);
+			}
+			if (decoder->contrast != pic->contrast) {
+				/* We want 0 to 127 we get 0-65535 */
+				decoder->contrast = pic->contrast;
+				saa7111_write(decoder, 0x0b, decoder->contrast >> 9);
+			}
+			if (decoder->sat != pic->colour) {
+				/* We want 0 to 127 we get 0-65535 */
+				decoder->sat = pic->colour;
+				saa7111_write(decoder, 0x0c, decoder->sat >> 9);
+			}
+			if (decoder->hue != pic->hue) {
+				/* We want -128 to 127 we get 0-65535 */
+				decoder->hue = pic->hue;
+				saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8);
+			}
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7111 =
+{
+	"saa7111",		/* name */
+	I2C_DRIVERID_VIDEODECODER,	/* ID */
+	I2C_SAA7111, I2C_SAA7111 + 1,
+
+	saa7111_attach,
+	saa7111_detach,
+	saa7111_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+int saa7111_init(void)
+#endif
+{
+	return i2c_register_driver(&i2c_driver_saa7111);
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	i2c_unregister_driver(&i2c_driver_saa7111);
+}
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/saa7185.c linux/drivers/char/saa7185.c
--- v2.3.9/linux/drivers/char/saa7185.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/saa7185.c	Mon Jul  5 20:07:02 1999
@@ -0,0 +1,379 @@
+/* 
+   saa7185 - Philips SAA7185B video encoder driver version 0.0.3
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.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 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/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
+
+#define DEBUG(x)   x		/* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct saa7185 {
+	struct i2c_bus *bus;
+	int addr;
+	unsigned char reg[128];
+
+	int norm;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+#define   I2C_SAA7185        0x88
+
+#define I2C_DELAY   10
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data)
+{
+	int ack;
+	unsigned long flags;
+
+	LOCK_I2C_BUS(dev->bus);
+
+	i2c_start(dev->bus);
+	i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+	i2c_sendbyte(dev->bus, subaddr, I2C_DELAY);
+	ack = i2c_sendbyte(dev->bus, data, I2C_DELAY);
+	dev->reg[subaddr] = data;
+	i2c_stop(dev->bus);
+	UNLOCK_I2C_BUS(dev->bus);
+	return ack;
+}
+
+static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len)
+{
+	int ack;
+	unsigned subaddr;
+	unsigned long flags;
+
+	while (len > 1) {
+		LOCK_I2C_BUS(dev->bus);
+		i2c_start(dev->bus);
+		i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY);
+		ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+		len -= 2;
+		while (len > 1 && *data == ++subaddr) {
+			data++;
+			ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY);
+			len -= 2;
+		}
+		i2c_stop(dev->bus);
+		UNLOCK_I2C_BUS(dev->bus);
+	}
+	return ack;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char init_common[] =
+{
+	0x3a, 0x0f,		/* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */
+
+	0x42, 0x6b,		/* OVLY0=107 */
+	0x43, 0x00,		/* OVLU0=0     white */
+	0x44, 0x00,		/* OVLV0=0   */
+	0x45, 0x22,		/* OVLY1=34  */
+	0x46, 0xac,		/* OVLU1=172   yellow */
+	0x47, 0x0e,		/* OVLV1=14  */
+	0x48, 0x03,		/* OVLY2=3   */
+	0x49, 0x1d,		/* OVLU2=29    cyan */
+	0x4a, 0xac,		/* OVLV2=172 */
+	0x4b, 0xf0,		/* OVLY3=240 */
+	0x4c, 0xc8,		/* OVLU3=200   green */
+	0x4d, 0xb9,		/* OVLV3=185 */
+	0x4e, 0xd4,		/* OVLY4=212 */
+	0x4f, 0x38,		/* OVLU4=56    magenta */
+	0x50, 0x47,		/* OVLV4=71  */
+	0x51, 0xc1,		/* OVLY5=193 */
+	0x52, 0xe3,		/* OVLU5=227   red */
+	0x53, 0x54,		/* OVLV5=84  */
+	0x54, 0xa3,		/* OVLY6=163 */
+	0x55, 0x54,		/* OVLU6=84    blue */
+	0x56, 0xf2,		/* OVLV6=242 */
+	0x57, 0x90,		/* OVLY7=144 */
+	0x58, 0x00,		/* OVLU7=0     black */
+	0x59, 0x00,		/* OVLV7=0   */
+
+	0x5a, 0x00,		/* CHPS=0    */
+	0x5b, 0x76,		/* GAINU=118 */
+	0x5c, 0xa5,		/* GAINV=165 */
+	0x5d, 0x3c,		/* BLCKL=60  */
+	0x5e, 0x3a,		/* BLNNL=58  */
+	0x5f, 0x3a,		/* CCRS=0, BLNVB=58 */
+	0x60, 0x00,		/* NULL      */
+
+/* 0x61 - 0x66 set according to norm */
+
+	0x67, 0x00,		/* 0 : caption 1st byte odd  field */
+	0x68, 0x00,		/* 0 : caption 2nd byte odd  field */
+	0x69, 0x00,		/* 0 : caption 1st byte even field */
+	0x6a, 0x00,		/* 0 : caption 2nd byte even field */
+
+	0x6b, 0x91,		/* MODIN=2, PCREF=0, SCCLN=17 */
+	0x6c, 0x20,		/* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */
+	0x6d, 0x00,		/* SRCM1=0, CCEN=0 */
+
+	0x6e, 0x0e,		/* HTRIG=0x00e, approx. centered, at least for PAL */
+	0x6f, 0x00,		/* HTRIG upper bits */
+	0x70, 0x20,		/* PHRES=0, SBLN=1, VTRIG=0 */
+
+/* The following should not be needed */
+
+	0x71, 0x15,		/* BMRQ=0x115 */
+	0x72, 0x90,		/* EMRQ=0x690 */
+	0x73, 0x61,		/* EMRQ=0x690, BMRQ=0x115 */
+	0x74, 0x00,		/* NULL       */
+	0x75, 0x00,		/* NULL       */
+	0x76, 0x00,		/* NULL       */
+	0x77, 0x15,		/* BRCV=0x115 */
+	0x78, 0x90,		/* ERCV=0x690 */
+	0x79, 0x61,		/* ERCV=0x690, BRCV=0x115 */
+
+/* Field length controls */
+
+	0x7a, 0x70,		/* FLC=0 */
+
+/* The following should not be needed if SBLN = 1 */
+
+	0x7b, 0x16,		/* FAL=22 */
+	0x7c, 0x35,		/* LAL=244 */
+	0x7d, 0x20,		/* LAL=244, FAL=22 */
+};
+
+static const unsigned char init_pal[] =
+{
+	0x61, 0x1e,		/* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
+	0x62, 0xc8,		/* DECTYP=1, BSTA=72 */
+	0x63, 0xcb,		/* FSC0 */
+	0x64, 0x8a,		/* FSC1 */
+	0x65, 0x09,		/* FSC2 */
+	0x66, 0x2a,		/* FSC3 */
+};
+
+static const unsigned char init_ntsc[] =
+{
+	0x61, 0x1d,		/* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */
+	0x62, 0xe6,		/* DECTYP=1, BSTA=102 */
+	0x63, 0x1f,		/* FSC0 */
+	0x64, 0x7c,		/* FSC1 */
+	0x65, 0xf0,		/* FSC2 */
+	0x66, 0x21,		/* FSC3 */
+};
+
+static int saa7185_attach(struct i2c_device *device)
+{
+	int i;
+	struct saa7185 *encoder;
+
+	device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL);
+	if (encoder == NULL) {
+		return -ENOMEM;
+	}
+	MOD_INC_USE_COUNT;
+
+	memset(encoder, 0, sizeof(struct saa7185));
+	strcpy(device->name, "saa7185");
+	encoder->bus = device->bus;
+	encoder->addr = device->addr;
+	encoder->norm = VIDEO_MODE_NTSC;
+	encoder->enable = 1;
+
+	i = saa7185_write_block(encoder, init_common, sizeof(init_common));
+	if (i >= 0) {
+		i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc));
+	}
+	if (i < 0) {
+		printk(KERN_ERR "%s_attach: init error %d\n", device->name, i);
+	}
+	return 0;
+}
+
+
+static int saa7185_detach(struct i2c_device *device)
+{
+	kfree(device->data);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg)
+{
+	struct saa7185 *encoder = device->data;
+
+	switch (cmd) {
+
+	case ENCODER_GET_CAPABILITIES:
+		{
+			struct video_encoder_capability *cap = arg;
+
+			cap->flags
+			    = VIDEO_ENCODER_PAL
+			    | VIDEO_ENCODER_NTSC
+			    | VIDEO_ENCODER_SECAM
+			    | VIDEO_ENCODER_CCIR;
+			cap->inputs = 1;
+			cap->outputs = 1;
+		}
+		break;
+
+	case ENCODER_SET_NORM:
+		{
+			int *iarg = arg;
+
+			switch (*iarg) {
+
+			case VIDEO_MODE_NTSC:
+				saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc));
+				break;
+
+			case VIDEO_MODE_PAL:
+				saa7185_write_block(encoder, init_pal, sizeof(init_pal));
+				break;
+
+			case VIDEO_MODE_SECAM:
+			default:
+				return -EINVAL;
+
+			}
+			encoder->norm = *iarg;
+		}
+		break;
+
+	case ENCODER_SET_INPUT:
+		{
+			int *iarg = arg;
+
+#if 0
+			/* not much choice of inputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+#else
+			/* RJ: *iarg = 0: input is from SA7111
+			   *iarg = 1: input is from ZR36060 */
+
+			switch (*iarg) {
+
+			case 0:
+				/* Switch RTCE to 1 */
+				saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
+				break;
+
+			case 1:
+				/* Switch RTCE to 0 */
+				saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
+				break;
+
+			default:
+				return -EINVAL;
+
+			}
+#endif
+		}
+		break;
+
+	case ENCODER_SET_OUTPUT:
+		{
+			int *iarg = arg;
+
+			/* not much choice of outputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+		}
+		break;
+
+	case ENCODER_ENABLE_OUTPUT:
+		{
+			int *iarg = arg;
+
+			encoder->enable = !!*iarg;
+			saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40));
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7185 =
+{
+	"saa7185",		/* name */
+	I2C_DRIVERID_VIDEOENCODER,	/* ID */
+	I2C_SAA7185, I2C_SAA7185 + 1,
+
+	saa7185_attach,
+	saa7185_detach,
+	saa7185_command
+};
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+int saa7185_init(void)
+#endif
+{
+	return i2c_register_driver(&i2c_driver_saa7185);
+}
+
+
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	i2c_unregister_driver(&i2c_driver_saa7185);
+}
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.9/linux/drivers/char/serial.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/serial.c	Thu Jul  1 15:09:01 1999
@@ -2380,7 +2380,6 @@
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
diff -u --recursive --new-file v2.3.9/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.3.9/linux/drivers/char/sysrq.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/sysrq.c	Sat Jul  3 10:42:21 1999
@@ -150,15 +150,6 @@
 
 /* Aux routines for the syncer */
 
-static void all_files_read_only(void)	    /* Kill write permissions of all files */
-{
-	struct file *file;
-
-	for (file = inuse_filps; file; file = file->f_next)
-		if (file->f_dentry && atomic_read(&file->f_count) && S_ISREG(file->f_dentry->d_inode->i_mode))
-			file->f_mode &= ~2;
-}
-
 static int is_local_disk(kdev_t dev)	    /* Guess if the device is a local hard drive */
 {
 	unsigned int major = MAJOR(dev);
@@ -192,6 +183,7 @@
 		struct super_block *sb = get_super(dev);
 		struct vfsmount *vfsmnt;
 		int ret, flags;
+		struct list_head *p;
 
 		if (!sb) {
 			printk("Superblock not found\n");
@@ -201,6 +193,15 @@
 			printk("R/O\n");
 			return;
 		}
+
+		file_list_lock();
+		for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+			struct file *file = list_entry(p, struct file, f_list);
+			if (file->f_dentry && file_count(file)
+				&& S_ISREG(file->f_dentry->d_inode->i_mode))
+				file->f_mode &= ~2;
+		}
+		file_list_unlock();
 		DQUOT_OFF(dev);
 		fsync_dev(dev);
 		flags = MS_RDONLY;
@@ -239,9 +240,6 @@
 	lock_kernel();
 	remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
 	emergency_sync_scheduled = 0;
-
-	if (remount_flag)
-		all_files_read_only();
 
 	for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
 		if (is_local_disk(mnt->mnt_dev))
diff -u --recursive --new-file v2.3.9/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.3.9/linux/drivers/char/tpqic02.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/tpqic02.c	Tue Jul  6 10:11:40 1999
@@ -127,7 +127,7 @@
 
 static volatile int ctlbits = 0;     /* control reg bits for tape interface */
 
-static wait_queue_t qic02_tape_transfer; /* sync rw with interrupts */
+static wait_queue_head_t qic02_tape_transfer; /* sync rw with interrupts */
 
 static volatile struct mtget ioctl_status;	/* current generic status */
 
@@ -2216,7 +2216,7 @@
     }
     
 	/* Only one at a time from here on... */
-    if (atomic_read(&filp->f_count)>1) 	/* filp->f_count==1 for the first open() */
+    if (file_count(filp)>1) 	/* filp->f_count==1 for the first open() */
     {
 	return -EBUSY;
     }
@@ -2889,7 +2889,7 @@
     return 0;
 } /* qic02_get_resources */
 
-__initfunc(int qic02_tape_init(void))
+int __init qic02_tape_init(void)
 {
     if (TPSTATSIZE != 6)
     {
diff -u --recursive --new-file v2.3.9/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.9/linux/drivers/char/tty_io.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/tty_io.c	Sun Jul  4 10:18:52 1999
@@ -173,13 +173,15 @@
 static int check_tty_count(struct tty_struct *tty, const char *routine)
 {
 #ifdef CHECK_TTY_COUNT
-	struct file *f;
+	struct list_head *p;
 	int count = 0;
 	
-	for(f = inuse_filps; f; f = f->f_next) {
-		if(f->private_data == tty)
+	file_list_lock();
+	for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) {
+		if(list_entry(p, struct file, f_list)->private_data == tty)
 			count++;
 	}
+	file_list_unlock();
 	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver.subtype == PTY_TYPE_SLAVE &&
 	    tty->link && tty->link->count)
@@ -383,9 +385,9 @@
 void do_tty_hangup(void *data)
 {
 	struct tty_struct *tty = (struct tty_struct *) data;
-	struct file * filp;
 	struct file * cons_filp = NULL;
 	struct task_struct *p;
+	struct list_head *l;
 	int    closecount = 0, n;
 
 	if (!tty)
@@ -395,13 +397,11 @@
 	lock_kernel();
 	
 	check_tty_count(tty, "do_tty_hangup");
-	for (filp = inuse_filps; filp; filp = filp->f_next) {
-		if (filp->private_data != tty)
-			continue;
+	file_list_lock();
+	for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
+		struct file * filp = list_entry(l, struct file, f_list);
 		if (!filp->f_dentry)
 			continue;
-		if (!filp->f_dentry->d_inode)
-			continue;
 		if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
 		    filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
 			cons_filp = filp;
@@ -410,9 +410,10 @@
 		if (filp->f_op != &tty_fops)
 			continue;
 		closecount++;
-		tty_fasync(-1, filp, 0);
+		tty_fasync(-1, filp, 0);	/* can't block */
 		filp->f_op = &hung_up_tty_fops;
 	}
+	file_list_unlock();
 	
 	/* FIXME! What are the locking issues here? This may me overdoing things.. */
 	{
@@ -1307,6 +1308,7 @@
 init_dev_done:
 #endif
 	filp->private_data = tty;
+	file_move(filp, &tty->tty_files);
 	check_tty_count(tty, "tty_open");
 	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver.subtype == PTY_TYPE_MASTER)
@@ -1788,6 +1790,10 @@
  * have to coordinate with the init process, since all processes associated
  * with the current tty must be dead before the new getty is allowed
  * to spawn.
+ *
+ * Now, if it would be correct ;-/ The current code has a nasty hole -
+ * it doesn't catch files in flight. We may send the descriptor to ourselves
+ * via AF_UNIX socket, close it and later fetch from socket. FIXME.
  */
 void do_SAK( struct tty_struct *tty)
 {
@@ -1812,6 +1818,7 @@
 		    ((session > 0) && (p->session == session)))
 			send_sig(SIGKILL, p, 1);
 		else if (p->files) {
+			read_lock(&p->files->file_lock);
 			for (i=0; i < p->files->max_fds; i++) {
 				filp = fcheck_task(p, i);
 				if (filp && (filp->f_op == &tty_fops) &&
@@ -1820,6 +1827,7 @@
 					break;
 				}
 			}
+			read_unlock(&p->files->file_lock);
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -1937,6 +1945,7 @@
 	tty->tq_hangup.routine = do_tty_hangup;
 	tty->tq_hangup.data = tty;
 	sema_init(&tty->atomic_read, 1);
+	INIT_LIST_HEAD(&tty->tty_files);
 }
 
 /*
diff -u --recursive --new-file v2.3.9/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.3.9/linux/drivers/char/videodev.c	Wed Jun  2 11:29:13 1999
+++ linux/drivers/char/videodev.c	Mon Jul  5 20:09:40 1999
@@ -63,6 +63,9 @@
 #ifdef CONFIG_RADIO_RTRACK
 extern int rtrack_init(struct video_init *);
 #endif
+#ifdef CONFIG_RADIO_RTRACK2
+extern int rtrack2_init(struct video_init *);
+#endif
 #ifdef CONFIG_RADIO_SF16FMI
 extern int fmi_init(struct video_init *);
 #endif
@@ -78,9 +81,15 @@
 #ifdef CONFIG_RADIO_CADET
 extern int cadet_init(struct video_init *);
 #endif
+#ifdef CONFIG_RADIO_TERRATEC
+extern int terratec_init(struct video_init *);
+#endif
 #ifdef CONFIG_VIDEO_PMS
 extern int init_pms_cards(struct video_init *);
 #endif
+#ifdef CONFIG_VIDEO_ZORAN
+extern int init_zoran_cards(struct video_init *);
+#endif
 
 static struct video_init video_init_list[]={
 #ifdef CONFIG_VIDEO_BT848
@@ -108,6 +117,9 @@
 #ifdef CONFIG_RADIO_RTRACK
 	{"RTrack", rtrack_init}, 
 #endif 
+#ifdef CONFIG_RADIO_RTRACK2
+	{"RTrack2", rtrack2_init}, 
+#endif
 #ifdef CONFIG_RADIO_SF16FMI
 	{"SF16FMI", fmi_init}, 
 #endif	
@@ -123,6 +135,12 @@
 #ifdef CONFIG_RADIO_TYPHOON
 	{"radio-typhoon", typhoon_init},
 #endif
+#ifdef CONFIG_RADIO_TERRATEC
+	{"radio-terratec", terratec_init},
+#endif
+#ifdef CONFIG_VIDEO_ZORAN
+	{"zoran", init_zoran_cards},
+#endif	
 	{"end", NULL}
 };
 
diff -u --recursive --new-file v2.3.9/linux/drivers/char/zr36057.h linux/drivers/char/zr36057.h
--- v2.3.9/linux/drivers/char/zr36057.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/zr36057.h	Mon Jul  5 20:09:40 1999
@@ -0,0 +1,168 @@
+/* 
+   zr36057.h - zr36057 register offsets
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.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 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.
+ */
+
+#ifndef _ZR36057_H_
+#define _ZR36057_H_
+
+
+/* Zoran ZR36057 registers */
+
+#define ZR36057_VFEHCR          0x000	/* Video Front End, Horizontal Configuration Register */
+#define ZR36057_VFEHCR_HSPol            (1<<30)
+#define ZR36057_VFEHCR_HStart           10
+#define ZR36057_VFEHCR_HEnd	        0
+#define ZR36057_VFEHCR_Hmask	        0x3ff
+
+#define ZR36057_VFEVCR          0x004	/* Video Front End, Vertical Configuration Register */
+#define ZR36057_VFEVCR_VSPol            (1<<30)
+#define ZR36057_VFEVCR_VStart           10
+#define ZR36057_VFEVCR_VEnd	        0
+#define ZR36057_VFEVCR_Vmask	        0x3ff
+
+#define ZR36057_VFESPFR         0x008	/* Video Front End, Scaler and Pixel Format Register */
+#define ZR36057_VFESPFR_ExtFl           (1<<26)
+#define ZR36057_VFESPFR_TopField        (1<<25)
+#define ZR36057_VFESPFR_VCLKPol         (1<<24)
+#define ZR36057_VFESPFR_HFilter         21
+#define ZR36057_VFESPFR_HorDcm          14
+#define ZR36057_VFESPFR_VerDcm          8
+#define ZR36057_VFESPFR_DispMode        6
+#define ZR36057_VFESPFR_YUV422          (0<<3)
+#define ZR36057_VFESPFR_RGB888          (1<<3)
+#define ZR36057_VFESPFR_RGB565          (2<<3)
+#define ZR36057_VFESPFR_RGB555          (3<<3)
+#define ZR36057_VFESPFR_ErrDif          (1<<2)
+#define ZR36057_VFESPFR_Pack24          (1<<1)
+#define ZR36057_VFESPFR_LittleEndian    (1<<0)
+
+#define ZR36057_VDTR            0x00c	/* Video Display "Top" Register */
+
+#define ZR36057_VDBR            0x010	/* Video Display "Bottom" Register */
+
+#define ZR36057_VSSFGR          0x014	/* Video Stride, Status, and Frame Grab Register */
+#define ZR36057_VSSFGR_DispStride       16
+#define ZR36057_VSSFGR_VidOvf           (1<<8)
+#define ZR36057_VSSFGR_SnapShot         (1<<1)
+#define ZR36057_VSSFGR_FrameGrab        (1<<0)
+
+#define ZR36057_VDCR            0x018	/* Video Display Configuration Register */
+#define ZR36057_VDCR_VidEn              (1<<31)
+#define ZR36057_VDCR_MinPix             24
+#define ZR36057_VDCR_Triton             (1<<24)
+#define ZR36057_VDCR_VidWinHt           12
+#define ZR36057_VDCR_VidWinWid          0
+
+#define ZR36057_MMTR            0x01c	/* Masking Map "Top" Register */
+
+#define ZR36057_MMBR            0x020	/* Masking Map "Bottom" Register */
+
+#define ZR36057_OCR             0x024	/* Overlay Control Register */
+#define ZR36057_OCR_OvlEnable           (1 << 15)
+#define ZR36057_OCR_MaskStride          0
+
+#define ZR36057_SPGPPCR         0x028	/* System, PCI, and General Purpose Pins Control Register */
+#define ZR36057_SPGPPCR_SoftReset	(1<<24)
+
+#define ZR36057_GPPGCR1         0x02c	/* General Purpose Pins and GuestBus Control Register (1) */
+
+#define ZR36057_MCSAR           0x030	/* MPEG Code Source Address Register */
+
+#define ZR36057_MCTCR           0x034	/* MPEG Code Transfer Control Register */
+#define ZR36057_MCTCR_CodTime           (1 << 30)
+#define ZR36057_MCTCR_CEmpty            (1 << 29)
+#define ZR36057_MCTCR_CFlush            (1 << 28)
+#define ZR36057_MCTCR_CodGuestID	20
+#define ZR36057_MCTCR_CodGuestReg	16
+
+#define ZR36057_MCMPR           0x038	/* MPEG Code Memory Pointer Register */
+
+#define ZR36057_ISR             0x03c	/* Interrupt Status Register */
+#define ZR36057_ISR_GIRQ1               (1<<30)
+#define ZR36057_ISR_GIRQ0               (1<<29)
+#define ZR36057_ISR_CodRepIRQ           (1<<28)
+#define ZR36057_ISR_JPEGRepIRQ          (1<<27)
+
+#define ZR36057_ICR             0x040	/* Interrupt Control Register */
+#define ZR36057_ICR_GIRQ1               (1<<30)
+#define ZR36057_ICR_GIRQ0               (1<<29)
+#define ZR36057_ICR_CodRepIRQ           (1<<28)
+#define ZR36057_ICR_JPEGRepIRQ          (1<<27)
+#define ZR36057_ICR_IntPinEn            (1<<24)
+
+#define ZR36057_I2CBR           0x044	/* I2C Bus Register */
+#define ZR36057_I2CBR_SDA       	(1<<1)
+#define ZR36057_I2CBR_SCL       	(1<<0)
+
+#define ZR36057_JMC             0x100	/* JPEG Mode and Control */
+#define ZR36057_JMC_JPG                 (1 << 31)
+#define ZR36057_JMC_JPGExpMode          (0 << 29)
+#define ZR36057_JMC_JPGCmpMode          (1 << 29)
+#define ZR36057_JMC_MJPGExpMode         (2 << 29)
+#define ZR36057_JMC_MJPGCmpMode         (3 << 29)
+#define ZR36057_JMC_RTBUSY_FB           (1 << 6)
+#define ZR36057_JMC_Go_en               (1 << 5)
+#define ZR36057_JMC_SyncMstr            (1 << 4)
+#define ZR36057_JMC_Fld_per_buff        (1 << 3)
+#define ZR36057_JMC_VFIFO_FB            (1 << 2)
+#define ZR36057_JMC_CFIFO_FB            (1 << 1)
+#define ZR36057_JMC_Stll_LitEndian      (1 << 0)
+
+#define ZR36057_JPC             0x104	/* JPEG Process Control */
+#define ZR36057_JPC_P_Reset             (1 << 7)
+#define ZR36057_JPC_CodTrnsEn           (1 << 5)
+#define ZR36057_JPC_Active              (1 << 0)
+
+#define ZR36057_VSP             0x108	/* Vertical Sync Parameters */
+#define ZR36057_VSP_VsyncSize           16
+#define ZR36057_VSP_FrmTot              0
+
+#define ZR36057_HSP             0x10c	/* Horizontal Sync Parameters */
+#define ZR36057_HSP_HsyncStart          16
+#define ZR36057_HSP_LineTot             0
+
+#define ZR36057_FHAP            0x110	/* Field Horizontal Active Portion */
+#define ZR36057_FHAP_NAX                16
+#define ZR36057_FHAP_PAX                0
+
+#define ZR36057_FVAP            0x114	/* Field Vertical Active Portion */
+#define ZR36057_FVAP_NAY                16
+#define ZR36057_FVAP_PAY                0
+
+#define ZR36057_FPP             0x118	/* Field Process Parameters */
+#define ZR36057_FPP_Odd_Even            (1 << 0)
+
+#define ZR36057_JCBA            0x11c	/* JPEG Code Base Address */
+
+#define ZR36057_JCFT            0x120	/* JPEG Code FIFO Threshold */
+
+#define ZR36057_JCGI            0x124	/* JPEG Codec Guest ID */
+#define ZR36057_JCGI_JPEGuestID         4
+#define ZR36057_JCGI_JPEGuestReg        0
+
+#define ZR36057_GCR2            0x12c	/* GuestBus Control Register (2) */
+
+#define ZR36057_POR             0x200	/* Post Office Register */
+#define ZR36057_POR_POPen               (1<<25)
+#define ZR36057_POR_POTime              (1<<24)
+#define ZR36057_POR_PODir               (1<<23)
+
+#define ZR36057_STR             0x300	/* "Still" Transfer Register */
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/char/zr36060.h linux/drivers/char/zr36060.h
--- v2.3.9/linux/drivers/char/zr36060.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/zr36060.h	Mon Jul  5 20:09:40 1999
@@ -0,0 +1,35 @@
+/* 
+   zr36060.h - zr36060 register offsets
+
+   Copyright (C) 1998 Dave Perks <dperks@ibm.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 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.
+ */
+
+#ifndef _ZR36060_H_
+#define _ZR36060_H_
+
+
+/* Zoran ZR36060 registers */
+
+#define ZR36060_LoadParameters  	0x000
+#define ZR36060_Load                    (1<<7)
+#define ZR36060_SyncRst                 (1<<0)
+
+#define ZR36060_CodeFifoStatus  	0x001
+#define ZR36060_Load                    (1<<7)
+#define ZR36060_SyncRst                 (1<<0)
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/fc4/socal.c linux/drivers/fc4/socal.c
--- v2.3.9/linux/drivers/fc4/socal.c	Sun Mar 28 09:07:47 1999
+++ linux/drivers/fc4/socal.c	Mon Jul  5 20:35:18 1999
@@ -37,7 +37,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/README linux/drivers/i2o/README
--- v2.3.9/linux/drivers/i2o/README	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/README	Mon Jul  5 20:09:40 1999
@@ -22,8 +22,15 @@
 Philip Rumpf
 	Fixed assorted dumb SMP locking bugs
 
-Juha Sievanen,  University Of Helsinki Finland
+Juha Sievanen,  University of Helsinki Finland
 	LAN OSM
+	/proc interface to LAN class
+	Bug fixes
+	Core code extensions
+
+Auvo Häkkinen,  University of Helsinki Finland
+	LAN OSM
+	/Proc interface to LAN class
 	Bug fixes
 	Core code extensions
 
@@ -41,13 +48,16 @@
 BoxHill Corporation
 	Loan of initial FibreChannel disk array used for development work.
 
+European Comission
+	Funding the work done by the University of Helsinki
+
 STATUS:
 
 o	The core setup works within limits.
 o	The scsi layer seems to almost work. I'm still chasing down the hang
 	bug.
 o	The block OSM is fairly minimal but does seem to work.
-
+o	LAN OSM works with FDDI cards.
 
 TO DO:
 
@@ -69,10 +79,8 @@
 SCSI:
 o	Find the right way to associate drives/luns/busses
 
-Net:
-o	Port the existing RCPCI work to the frame work or write a new
-	driver. This one is with the Finns
+Lan:	Batch mode sends
+	Fix the "killing interrupt handler" in i2o_set_multicast_list
 
 Tape:
 o	Anyone seen anything implementing this ?
-
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/README.lan linux/drivers/i2o/README.lan
--- v2.3.9/linux/drivers/i2o/README.lan	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/README.lan	Mon Jul  5 20:09:40 1999
@@ -1,5 +1,6 @@
 
 	Linux I2O LAN OSM
+
 	(c) University of Helsinki, Department of Computer Science
 
 	This program is free software; you can redistribute it and/or
@@ -8,14 +9,14 @@
 	2 of the License, or (at your option) any later version.
 
 AUTHORS
-Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI
-Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI
+	Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI
+	Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI
 
 CREDITS
 
 	This work was made possible by 
 
-European Committee
+European Commission
 	Funding for the project
 
 SysKonnect
@@ -32,7 +33,6 @@
 
 LAN:
 o	Add support for bactches
-o	Find why big packets flow from I2O box out, but don't want to come in
 o	Find the bug in i2o_set_multicast_list(), which kills interrupt
 	handler in i2o_wait_reply()
 o	Add support for Ethernet, Token Ring, AnyLAN, Fibre Channel
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.9/linux/drivers/i2o/i2o_block.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_block.c	Mon Jul  5 20:09:40 1999
@@ -10,13 +10,17 @@
  * 	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
- *	This is an initial test release. Most of the good code was taken
+ *	This is a beta test release. Most of the good code was taken
  *	from the nbd driver by Pavel Machek, who in turn took some of it
  *	from loop.c. Isn't free software great for reusability 8)
  *
  *	Fixes:
  *		Steve Ralston:	Multiple device handling error fixes,
  *				Added a queue depth.
+ *
+ *	Todo:
+ *		64bit cleanness.
+ *		Remove the queue walk. We can do that better.
  */
 
 #include <linux/major.h>
@@ -31,6 +35,7 @@
 #include <linux/ioctl.h>
 #include <linux/i2o.h>
 #include <linux/blkdev.h>
+#include <linux/blkpg.h>
 #include <linux/malloc.h>
 #include <linux/hdreg.h>
 
@@ -47,7 +52,7 @@
 
 #define MAX_I2OB	16
 
-#define MAX_I2OB_DEPTH	4
+#define MAX_I2OB_DEPTH	8
 
 /*
  *	Some of these can be made smaller later
@@ -61,9 +66,7 @@
 
 static int i2ob_context;
 
-#ifdef __SMP__
 static spinlock_t i2ob_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 struct i2ob_device
 {
@@ -175,15 +178,10 @@
 		msg[5] -= count;
 	}
 
-//	printk("Send for %p\n", req);
-
 	i2o_post_message(c,m);
 	atomic_inc(&queue_depth);
 	if(atomic_read(&queue_depth)>old_qd)
-	{
 		old_qd=atomic_read(&queue_depth);
-		printk("Depth now %d.\n", old_qd);
-	}
 	return 0;
 }
 
@@ -825,7 +823,7 @@
                                  */
                                 if(i2ob_claim_device(dev, 1)==0)
                                 {
-                                        printk(KERN_INFO "Claimed Dev %x Tid %d Unit %d\n",dev,dev->tid,unit);
+                                        printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit);
                                         i2ob_install_device(c,d,unit);
                                         unit+=16;
  
@@ -836,7 +834,7 @@
                                          * the block or scsi driver.
                                          */
                                         if (i2ob_claim_device(dev, 0)<0)
-                                                printk(KERN_INFO "Could not unclaim Dev %x Tid %d\n",dev,dev->tid);
+                                                printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid);
  
                                 }
                                 else
@@ -966,14 +964,14 @@
  */
 
 #ifdef MODULE
-#define i2ob_init init_module
+#define i2o_block_init init_module
 #endif
 
-int i2ob_init(void)
+int i2o_block_init(void)
 {
 	int i;
 
-	printk("I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n");
+	printk(KERN_INFO "I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n");
 	
 	/*
 	 *	Register the block device interfaces
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.9/linux/drivers/i2o/i2o_config.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/i2o/i2o_config.c	Mon Jul  5 20:35:18 1999
@@ -5,8 +5,10 @@
  *	
  *	Written by Alan Cox, Building Number Three Ltd
  *
- *      Modified 04/20/199 by Deepak Saxena
+ *      Modified 04/20/1999 by Deepak Saxena
  *         - Added basic ioctl() support
+ *      Modified 06/07/1999 by Deepak Saxena
+ *         - Added software download ioctl (still testing)
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -22,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/miscdevice.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
 
 #include <asm/uaccess.h>
@@ -210,7 +211,10 @@
 	workspace = kmalloc(8192, GFP_KERNEL);
 	hrt = (pi2o_hrt)workspace;
 	if(workspace==NULL)
+	{
+		i2o_unlock_controller(c);
 		return -ENOMEM;
+	}
 
 	memset(workspace, 0, 8192);
 
@@ -271,7 +275,10 @@
 	workspace = kmalloc(8192, GFP_KERNEL);
 	lct = (pi2o_lct)workspace;
 	if(workspace==NULL)
+	{
+		i2o_unlock_controller(c);
 		return -ENOMEM;
+	}
 
 	memset(workspace, 0, 8192);
 
@@ -337,10 +344,14 @@
 
 	ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL);
 	if(!ops)
+	{
+		i2o_unlock_controller(c);
 		return -ENOMEM;
+	}
 
 	if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen))
 	{
+		i2o_unlock_controller(c);
 		kfree(ops);
 		return -EFAULT;
 	}
@@ -352,6 +363,7 @@
 	res = (u8*)kmalloc(65536, GFP_KERNEL);
 	if(!res)
 	{
+		i2o_unlock_controller(c);
 		kfree(ops);
 		return -ENOMEM;
 	}
@@ -374,11 +386,12 @@
 	token = i2o_post_wait(c, kcmd.tid, msg, 9*4, &i2o_cfg_token,10);
 	if(token == I2O_POST_WAIT_TIMEOUT)
 	{
+		i2o_unlock_controller(c);
 		kfree(ops);
 		kfree(res);
 		return -ETIMEDOUT;
 	}
-
+	i2o_unlock_controller(c);
 	kfree(ops);
 
 	/* 
@@ -448,9 +461,13 @@
 	{
 		query = kmalloc(kcmd.qlen, GFP_KERNEL);
 		if(!query)
+		{
+			i2o_unlock_controller(c);
 			return -ENOMEM;
+		}
 		if(copy_from_user(query, kcmd.qbuf, kcmd.qlen))
 		{
+			i2o_unlock_controller(c);
 			printk(KERN_INFO "i2o_config: could not get query\n");
 			kfree(query);
 			return -EFAULT;
@@ -459,7 +476,10 @@
 
 	res = kmalloc(4096, GFP_KERNEL);
 	if(!res)
+	{
+		i2o_unlock_controller(c);
 		return -ENOMEM;
+	}
 
 	msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid;
 	msg[2] = i2o_cfg_context;
@@ -480,11 +500,13 @@
 	token = i2o_post_wait(c, cmd->tid, msg, 9*4, &i2o_cfg_token, 10);
 	if(token == I2O_POST_WAIT_TIMEOUT)
 	{
+		i2o_unlock_controller(c);
 		kfree(res);
 		if(kcmd.qlen) kfree(query);
 
 		return -ETIMEDOUT;
 	}
+	i2o_unlock_controller(c);
 
 	len = strnlen(res, 8192);
 	put_user(len, kcmd.reslen);
@@ -500,10 +522,123 @@
 	return ret;
 }
 
-/* To be written */
 int ioctl_swdl(unsigned long arg)
 {
-	return -ENOSYS;
+	struct i2o_sw_xfer kxfer;
+	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+	unsigned char maxfrag = 0, curfrag = 0;
+	unsigned char buffer[8192];
+	u32 msg[MSG_FRAME_SIZE/4];
+	unsigned int token = 0, diff = 0, swlen = 0, swxfer = 0;
+	struct i2o_controller *c;
+	int foo = 0;
+
+	printk("*** foo%d ***\n", foo++);
+	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+	{
+		printk( "i2o_config: can't copy i2o_sw cmd @ %p\n", pxfer);
+		return -EFAULT;
+	}
+	printk("*** foo%d ***\n", foo++);
+
+	printk("Attempting to copy swlen from %p\n", kxfer.swlen);
+	if(get_user(swlen, kxfer.swlen) < 0)
+	{
+		printk( "i2o_config: can't copy swlen\n");
+		return -EFAULT;
+	}
+	printk("*** foo%d ***\n", foo++);
+
+	maxfrag = swlen >> 13;	// Transfer in 8k fragments
+
+	printk("Attempting to write maxfrag @ %p\n", kxfer.maxfrag);
+	if(put_user(maxfrag, kxfer.maxfrag) < 0)
+	{
+		printk( "i2o_config: can't write maxfrag\n");
+		return -EFAULT;
+	}
+	printk("*** foo%d ***\n", foo++);
+
+	printk("Attempting to write curfrag @ %p\n", kxfer.curfrag);
+	if(put_user(curfrag, kxfer.curfrag) < 0)
+	{
+		printk( "i2o_config: can't write curfrag\n");
+		return -EFAULT;
+	}
+	printk("*** foo%d ***\n", foo++);
+
+	if(!kxfer.buf)
+	{
+		printk( "i2o_config: NULL software buffer\n");
+		return -EFAULT;
+	}
+	printk("*** foo%d ***\n", foo++);
+	
+	// access_ok doesn't check for NULL...
+	if(!access_ok(VERIFY_READ, kxfer.buf, swlen))
+	{
+                printk( "i2o_config: Cannot read sw buffer\n");
+                return -EFAULT;
+	}
+	printk("*** foo%d ***\n", foo++);
+
+	c = i2o_find_controller(kxfer.iop);
+	if(!c)
+		return -ENXIO;
+	printk("*** foo%d ***\n", foo++);
+
+	msg[0]= EIGHT_WORD_MSG_SIZE| SGL_OFFSET_7;
+	msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= (u32)cfg_handler.context;
+	msg[3]= 0;
+	msg[4]= ((u32)kxfer.dl_flags)<<24|((u32)kxfer.sw_type)<<16|((u32)maxfrag)<<8|((u32)curfrag);
+	msg[5]= swlen;
+	msg[6]= kxfer.sw_id;
+	msg[7]= (0xD0000000 | 8192);
+	msg[8]= virt_to_phys(buffer);
+
+	printk("*** foo%d ***\n", foo++);
+
+	//
+	// Loop through all fragments but last and transfer them...
+	// We already checked memory, so from now we assume it's all good
+	//
+	for(curfrag = 0; curfrag < maxfrag-1; curfrag++)
+	{
+		printk("Transfering fragment %d\n", curfrag);
+
+		msg[4] |= (u32)curfrag;
+
+		__copy_from_user(buffer, kxfer.buf, 8192);
+		swxfer += 8129;
+
+		// Yes...that's one minute, but the spec states that
+		// transfers take a long time, and I've seen just how
+		// long they can take.
+		token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,60);
+		if( token == I2O_POST_WAIT_TIMEOUT )	// Something very wrong
+		{
+			printk("Timeout downloading software");
+			return -ETIMEDOUT;
+		}
+
+		__put_user(curfrag, kxfer.curfrag);
+	}
+
+	// Last frag is special case since it's not exactly 8K
+	diff = swlen - swxfer;
+	msg[4] |= (u32)maxfrag;
+	msg[7] = (0xD0000000 | diff);
+	__copy_from_user(buffer, kxfer.buf, 8192);
+	token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,60);
+	if( token == I2O_POST_WAIT_TIMEOUT )	// Something very wrong
+	{
+		printk("Timeout downloading software");
+		return -ETIMEDOUT;
+	}
+	__put_user(curfrag, kxfer.curfrag);
+
+	return 0;
 }
 
 /* To be written */
@@ -557,7 +692,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-int i2o_config_init(void)
+__init int i2o_config_init(void)
 #endif
 {
 	printk(KERN_INFO "i2o configuration manager v 0.02\n");
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.9/linux/drivers/i2o/i2o_core.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/i2o/i2o_core.c	Tue Jul  6 10:11:40 1999
@@ -13,12 +13,12 @@
  *	A lot of the I2O message side code from this is taken from the
  *	Red Creek RCPCI45 adapter driver by Red Creek Communications
  *
- *	Some fixes and cleanup by Philipp Rumpf
- *
- *	Additional fixes by Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *	
+ *	Fixes by Philipp Rumpf
+ *		 Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *	         Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
  */
  
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -32,26 +32,69 @@
 
 #include "i2o_lan.h"
 
+
 /*
  *	Size of the I2O module table
  */
  
-
 static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
 static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
 int i2o_num_controllers = 0;
-
+static int core_context = 0;
+static int reply_flag = 0;
 
 extern int i2o_online_controller(struct i2o_controller *c);
+static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
+			   struct i2o_message *);
+
+/* Message handler */ 
+static struct i2o_handler i2o_core_handler =
+{
+	(void *)i2o_core_reply,
+	"I2O core layer",
+	0
+};
 
 /*
  *	I2O configuration spinlock. This isnt a big deal for contention
  *	so we have one only
  */
  
-#ifdef __SMP__
 static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED;
+
+void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
+		    struct i2o_message *m)
+{
+	u32 *msg=(u32 *)m;
+	u32 *flag = (u32 *)msg[3];
+
+#if 0
+	i2o_report_status(KERN_INFO, "i2o_core", msg);
 #endif
+	
+	if (msg[0] & (1<<13)) // Fail bit is set
+        {
+                printk(KERN_ERR "IOP failed to process the msg:\n");
+                printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
+		       (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
+		       0xFFF);
+                printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
+		       "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+		       msg[4] >> 24, (msg[4] >> 16) & 0xFF,
+		       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+                printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+		       msg[5] >> 16, msg[5] & 0xFFF);
+                return;
+        }
+
+	if (msg[4] >> 24)
+	{
+		i2o_report_status(KERN_WARNING, "i2o_core", msg);
+		*flag = -(msg[4] & 0xFFFF);
+	}
+	else
+		*flag = I2O_POST_WAIT_OK;
+}
 
 /*
  *	Install an I2O handler - these handle the asynchronous messaging
@@ -179,10 +222,11 @@
 int i2o_delete_controller(struct i2o_controller *c)
 {
 	struct i2o_controller **p;
-	
+
 	spin_lock(&i2o_configuration_lock);
 	if(atomic_read(&c->users))
 	{
+		printk("Someones using controller iop%d\n", c->unit);
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
@@ -195,21 +239,41 @@
 			return -EBUSY;
 		}
 	}
-	c->destructor(c);
-	
+//	c->destructor(c); /* We dont want to free the IRQ yet */
+
 	p=&i2o_controller_chain;
-	
+
+	/* Send first SysQuiesce to other IOPs */
+	while(*p)
+	{
+		if(*p!=c)
+			if(i2o_quiesce_controller(*p)<0)
+				printk(KERN_INFO "Unable to quiesce iop%d\n",
+				       (*p)->unit);
+		p=&((*p)->next);
+	}
+
+	p=&i2o_controller_chain;
+
 	while(*p)
 	{
 		if(*p==c)
 		{
-			/* Prepare for restart */
-//			i2o_clear_controller(c);
+			/* Ask the IOP to switch to HOLD state */
+			if (i2o_clear_controller(c) < 0)
+				printk("Unable to clear iop%d\n", c->unit);
+
+			/* Release IRQ */
+			c->destructor(c);
 
 			*p=c->next;
 			spin_unlock(&i2o_configuration_lock);
 			if(c->page_frame);
 				kfree(c->page_frame);
+			if(c->hrt)
+				kfree(c->hrt);
+			if(c->lct)
+				kfree(c->lct);
 			i2o_controllers[c->unit]=NULL;
 			kfree(c);
 			i2o_num_controllers--;
@@ -317,7 +381,7 @@
 		"Device Driver Module",
 		"Block Device",
 		"Tape Device",
-		"LAN Inteface",
+		"LAN Interface",
 		"WAN Interface",
 		"Fibre Channel Port",
 		"Fibre Channel Device",
@@ -384,7 +448,7 @@
 	{
 		if((jiffies-time)>=5*HZ)
 		{
-			printk(KERN_ERR "%s: Timeout waiting for message to send %s.\n", 
+			printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", 
 				c->name, why);
 			return 0xFFFFFFFF;
 		}
@@ -396,7 +460,7 @@
 
 
 /*
- *	Wait up to 5 seconds for a reply to be available.
+ *	Wait up to timeout seconds for a reply to be available.
  */
  
 u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
@@ -418,173 +482,6 @@
 }
 	
 
-
-/* Quiesce and clear IOP  */
-int i2o_quiesce_controller(struct i2o_controller *c)
-{
-	u32 m;
-	u32 *msg;
-
-	/* now we stop receiving messages to this IOP */
-	m=i2o_wait_message(c, "Quiesce IOP");
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-
-	msg=(u32 *)(c->mem_offset+m);
-
-	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=0;
-	msg[3]=0;
-
-	printk(KERN_DEBUG "Sending SysQuiesce to %s\n", c->name);
-	i2o_post_message(c,m);
-
-	m=i2o_wait_reply(c, "System Quiesce", 20);
-
-	if (m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-	/* Someday we should check return status... */
-
-	return 0;
-}
-
-int i2o_clear_controller(struct i2o_controller *c)
-{
-	u32 m;
-	u32 *msg;
-
-	m=i2o_wait_message(c, "IOP Clear");
-	if (m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-
-	msg=(u32 *)(c->mem_offset+m);
-
-	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=0;
-	msg[3]=0;
-
-	printk(KERN_DEBUG "Sending IOPClear to %s\n", c->name);
-	i2o_post_message(c, m);
-
-	m=i2o_wait_reply(c, "IOP Clear timeout", 5);
-
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-
-/*
- *	i2o table walking. We just provide a single element retrieve. You can
- *	all sorts of fancy lookups in I2O but we have no performance critical
- *	lookups so why write all the code for it.
- */
- 
-#if 0
-static int i2o_query_table_polled(struct i2o_controller *c, int tid, void *buf, int buflen, 
-	int group, int field, u32 *key, int keylen)
-{
-	u32 m;
-	u32 *msg;
-	u16 op[64];
-	u32 *p;
-	int i;
-	u32 *rbuf;
-
-	op[0]=1;			/* One Operation */
-	op[1]=0;			/* PAD */
-	op[2]=2;			/* LIST_GET */
-	op[3]=group;			/* group number */
-	op[4]=1;			/* 1 field */
-	op[5]=field;			/* Field number */
-	op[6]=1;			/* Key count */
-	memcpy(op+7, key, keylen);	/* Key */
-	
-	m=i2o_wait_message(c, "I2O query table.");
-	if(m==0xFFFFFFFF)
-	{	
-		return -ETIMEDOUT;
-	}
-	
-	msg=(u32 *)(c->mem_offset+m);
-	
-	rbuf=kmalloc(buflen+32, GFP_KERNEL);
-	if(rbuf==NULL)
-	{
-		printk(KERN_ERR "No free memory for table read.\n");
-		return -ENOMEM;
-	}
-	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-	msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid;
-	msg[2]=0;			/* Context */
-	msg[3]=0;
-	msg[4]=0;
-	msg[5]=0x54000000|(14);
-	msg[6]=virt_to_bus(op);
-	msg[7]=0xD0000000|(32+buflen);
-	msg[8]=virt_to_bus(rbuf);
-
-	i2o_post_message(c,m);
-	barrier();
-	
-	/*
-	 *	Now wait for a reply
-	 */
-	 
-	
-	m=i2o_wait_reply(c, "Table read timeout", 5);
-	
-	if(m==0xFFFFFFFF)
-	{
-		kfree(rbuf);
-		return -ETIMEDOUT;
-	}
-	
-	msg = (u32 *)bus_to_virt(m);
-
-	if(msg[4]>>24)
-	{
-		i2o_report_status(KERN_WARNING, "i2o_core",
-				  (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-				  msg[4]&0xFFFF);
-	}
-	
-	p=rbuf;
-
-	/* Ok 'p' is the reply block - lets see what happened */
-	/* p0->p2 are the header */
-	
-	/* FIXME: endians - turn p3 to little endian */
-	
-	i=(p[0]&0xFFFF)<<2;		/* Message size */
-	if(i<buflen)
-		buflen=i;
-	
-	/* Do we have an error block ? */
-	if(p[0]&0xFF000000)
-	{
-		printk(KERN_ERR "%s: error in field read.\n",
-			c->name);
-		kfree(rbuf);
-		return -EBADR;
-	}
-		
-	/* p[1] holds the more flag and row count - we dont care */
-	
-	/* Ok it worked p[2]-> hold the data */
-	memcpy(buf,  p+2, buflen);
-	
-	kfree(rbuf);
-	
-	/* Finally return the message */
-	I2O_REPLY_WRITE32(c,m);
-	return buflen;
-}
-#endif
-
 static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, 
 	int group, int field)
 {
@@ -602,7 +499,7 @@
 	op[4]=1;			/* 1 field */
 	op[5]=field;			/* Field number */
 
-	m=i2o_wait_message(c, "I2O query scalar.");
+	m=i2o_wait_message(c, "ParamsGet");
 	if(m==0xFFFFFFFF)
 	{	
 		return -ETIMEDOUT;
@@ -634,8 +531,7 @@
 	 *	Now wait for a reply
 	 */
 	 
-	
-	m=i2o_wait_reply(c, "Scalar read timeout", 5);
+	m=i2o_wait_reply(c, "ParamsGet", 5);
 	
 	if(m==0xFFFFFFFF)
 	{
@@ -646,9 +542,7 @@
 	msg = (u32 *)bus_to_virt(m);
 	if(msg[4]>>24)
 	{
-		i2o_report_status(KERN_WARNING, "i2o_core",
-				  (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-				  msg[4]&0xFFFF);
+		i2o_report_status(KERN_WARNING, "i2o_core", msg);
 	}
 	
 	p=rbuf;
@@ -729,9 +623,10 @@
  *	This is full of endianisms!
  */
  
-static int i2o_parse_hrt(struct i2o_controller *c, u8 *p)
+static int i2o_parse_hrt(struct i2o_controller *c)
 {
-	u32 *rows=(u32 *)p;
+	u32 *rows=c->hrt;
+	u8 *p=(u8 *)c->hrt;
 	u8 *d;
 	int count;
 	int length;
@@ -818,7 +713,7 @@
  *	on the board. Most of the stuff isn't interesting to us. 
  */
 
-static int i2o_parse_lct(struct i2o_controller *c, u32 *lct)
+static int i2o_parse_lct(struct i2o_controller *c)
 {
 	int i;
 	int max;
@@ -826,11 +721,18 @@
 	u32 *p;
 	struct i2o_device *d;
 	char str[22];
+	u32 *lct=(u32 *)c->lct;
 
 	max=lct[0]&0xFFFF;
 	
 	max-=3;
 	max/=9;
+
+	if(max==0)
+	{
+		printk(KERN_ERR "LCT is empty????\n");
+		return -1;
+	}
 	
 	printk(KERN_INFO "LCT has %d entries.\n", max);
 	
@@ -891,37 +793,61 @@
 	return 0;
 }
 
-#if 0
-/* Reset the IOP to sane state */
-/* I think we need handler for core (or executive class in I2O terms) */
-static int i2o_reset_adapter(struct i2o_controller *c)
+/* Quiesce IOP */
+int i2o_quiesce_controller(struct i2o_controller *c)
 {
-	u32 m;
-	u8 *work8;
-	u32 *msg;
-	long time;
+	u32 msg[4];
 
-	/* First stop extral operations */
-	m=i2o_wait_message(c, "quiesce IOP");
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-	
-	msg=(u32 *)(c->mem_offset+m);
-				
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=0;
-	msg[3]=0;
+	msg[2]=core_context;
+	msg[3]=(u32)&reply_flag;
 
-	i2o_post_message(c,m);
+	return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10);
+}
 
-	m=i2o_wait_reply(c, "System Quiesce timeout", 5);
 
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;
+int i2o_clear_controller(struct i2o_controller *c)
+{
+	u32 msg[4];
+
+	/* First stop external operations for this IOP */
+	if(i2o_quiesce_controller(c)<0)
+		printk(KERN_INFO "Unable to quiesce iop%d\n", c->unit);
+	else
+		printk(KERN_INFO "Iop%d quiesced\n", c->unit);
+
+	/* Then clear the IOP */
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]=core_context;
+	msg[3]=(u32)&reply_flag;
+
+	return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10);
+}
+
+
+/* Reset the IOP to sane state */
+static int i2o_reset_controller(struct i2o_controller *c)
+{
+	u32 m;
+	u8 *work8;
+	u32 *msg;
+	long time;
+	struct i2o_controller *iop;
+
+	/* 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);
+	}
 
 	/* Then reset the IOP */
-	m=i2o_wait_message(c, "reset IOP");
+	m=i2o_wait_message(c, "AdapterReset");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
 
@@ -937,8 +863,8 @@
 	
 	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=0;
-	msg[3]=0;
+	msg[2]=core_context;
+	msg[3]=(u32)&reply_flag;
 	msg[4]=0;
 	msg[5]=0;
 	msg[6]=virt_to_phys(work8);
@@ -949,8 +875,10 @@
 	/* Wait for a reply */
 	time=jiffies;
 
-	while(work8[0]==0x01) {
-		if((jiffies-time)>=5*HZ) {
+	while(work8[0]==0x01)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
 			printk(KERN_ERR "IOP reset timeout.\n");
 			kfree(work8);
 			return -ETIMEDOUT;
@@ -964,113 +892,186 @@
 
 	return 0;
 }
-#endif
 
-/*
- *	Bring an I2O controller into HOLD state. See the 1.5
- *	spec. Basically we go
- *
- *	Wait for the message queue to initialise. 
- *	If it didnt -> controller is dead
- *	
- *	Send a get status using the message queue
- *	Poll for a reply block 88 bytes long
- *
- *	Send an initialise outbound queue
- *	Poll for a reply
- *
- *	Post our blank messages to the queue FIFO
- *
- *	Send GetHRT, Parse it
- */
 
-int i2o_activate_controller(struct i2o_controller *c)
+int i2o_status_get(struct i2o_controller *c)
 {
 	long time;
 	u32 m;
-	u8 *workspace;
 	u32 *msg;
-	int i;
-	
-	printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", (u32)c->mem_phys);
+	u8 *status_block;
 
-	/* First reset the IOP to sane state */
-//	i2o_reset_adapter(c)
-	
-	m=i2o_wait_message(c, "initialise");
+	status_block=(void *)kmalloc(88, GFP_KERNEL);
+	if(status_block==NULL)
+	{
+		printk(KERN_ERR "StatusGet failed - no free memory.\n");
+		return -ENOMEM;
+	}
+
+	m=i2o_wait_message(c, "StatusGet");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
 
 	msg=(u32 *)(c->mem_offset+m);
-	
-	workspace = (void *)kmalloc(88, GFP_KERNEL);
-	if(workspace==NULL)
-	{
-		printk(KERN_ERR "IOP initialisation failed - no free memory.\n");
-		return -ENOMEM;
-	}
-	
-	memset(workspace, 0, 88);
-	
+
 	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
-	msg[2]=0;
+	msg[2]=core_context;
 	msg[3]=0;
 	msg[4]=0;
 	msg[5]=0;
-	msg[6]=virt_to_phys(workspace);
+	msg[6]=virt_to_phys(status_block);
 	msg[7]=0;	/* 64bit host FIXME */
 	msg[8]=88;
 
 	i2o_post_message(c,m);
 
-	/*
-	 *	Wait for a reply
-	 */
-
+	/* Wait for a reply */
 	time=jiffies;
 		 
-	while(workspace[87]!=0xFF)
+	while(status_block[87]!=0xFF)
 	{
 		if((jiffies-time)>=5*HZ)
 		{
 			printk(KERN_ERR "IOP get status timeout.\n");
-			kfree(workspace);
 			return -ETIMEDOUT;
 		}
 		schedule();
 		barrier();
 	}
 	
-	/*
-	 *	Ok the reply has arrived. Fill in the important stuff
-	 */
-	 
-	c->status = workspace[10];
-	c->i2oversion = (workspace[9]>>4)&0xFF;
-	c->inbound_size = (workspace[12]|(workspace[13]<<8))*4; /* 32bit words */
-	
+	/* Ok the reply has arrived. Fill in the important stuff */
+	c->status = status_block[10];
+	c->i2oversion = (status_block[9]>>4)&0xFF;
+	c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
+
+	return 0;
+}
+
+
+int i2o_hrt_get(struct i2o_controller *c)
+{
+	u32 m;
+	u32 *msg;
+
+	c->hrt=kmalloc(2048, GFP_KERNEL);
+	if(c->hrt==NULL)
+	{
+		printk(KERN_ERR "IOP init failed; no memory.\n");
+		return -ENOMEM;
+	}
+
+	m=i2o_wait_message(c, "HRTGet");
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;
+
+	msg=(u32 *)(c->mem_offset+m);
+
+	msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+	msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= core_context;
+	msg[3]= 0x0;				/* Transaction context */
+	msg[4]= (0xD0000000 | 2048);		/* Simple transaction , 2K */
+	msg[5]= virt_to_phys(c->hrt);		/* Dump it here */
+
+	i2o_post_message(c,m);
+
+	barrier();
+
+	/* Now wait for a reply */
+	m=i2o_wait_reply(c, "HRTGet", 5);
+
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;
+
+	msg=(u32 *)bus_to_virt(m);
+
+	if(msg[4]>>24)
+		i2o_report_status(KERN_WARNING, "i2o_core", msg);
+
+	I2O_REPLY_WRITE32(c,m);
+
+	return 0;
+}
+
+
+/*
+ *	Bring an I2O controller into HOLD state. See the 1.5
+ *	spec. Basically we go
+ *
+ *	Wait for the message queue to initialise. 
+ *	If it didnt -> controller is dead
+ *	
+ *	Send a get status using the message queue
+ *	Poll for a reply block 88 bytes long
+ *
+ *	Send an initialise outbound queue
+ *	Poll for a reply
+ *
+ *	Post our blank messages to the queue FIFO
+ *
+ *	Send GetHRT, Parse it
+ */
+
+int i2o_activate_controller(struct i2o_controller *c)
+{
+	long time;
+	u32 m;
+	u8 *workspace;
+	u32 *msg;
+	int i;
+	int ret;
+
+	printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n",
+	       (u32)c->mem_phys);
+
+	if((ret=i2o_status_get(c)))
+		return ret;
+
+	if(c->status == ADAPTER_STATE_FAULTED) /* not likely to be seen */
+	{
+		printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
+		       c->unit);
+		return -1;
+	}
+
 	/*
 	 *	If the board is running, reset it - we have no idea
 	 *	what kind of a mess the previous owner left it in.
 	 */
-	 
-//	if(c->status == ADAPTER_STATE_OPERATIONAL)
-//		i2o_reset_device(c);
+	if(c->status == ADAPTER_STATE_HOLD ||
+	   c->status == ADAPTER_STATE_READY ||
+	   c->status == ADAPTER_STATE_OPERATIONAL ||
+	   c->status == ADAPTER_STATE_FAILED)
+	{
+		if((ret=i2o_reset_controller(c)))
+			return ret;
 
-	
-	m=i2o_wait_message(c, "initqueue");
+		if((ret=i2o_status_get(c)))
+			return ret;
+	}
+
+	workspace = (void *)kmalloc(88, GFP_KERNEL);
+	if(workspace==NULL)
+	{
+		printk(KERN_ERR "IOP initialisation failed - no free memory.\n");
+		return -ENOMEM;
+	}
+
+	memset(workspace, 0, 88);
+
+	m=i2o_wait_message(c, "OutboundInit");
 	if(m==0xFFFFFFFF)
 	{	
 		kfree(workspace);
 		return -ETIMEDOUT;
 	}
-	
+
 	msg=(u32 *)(c->mem_offset+m);
 
 	msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
 	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2]= 0;
+	msg[2]= core_context;
 	msg[3]= 0x0106;			/* Transaction context */
 	msg[4]= 4096;			/* Host page frame size */
 	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size and Initcode */
@@ -1099,9 +1100,11 @@
 		schedule();
 		barrier();
 	}
-	
+
 	kfree(workspace);
 
+	/* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */
+
 	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
 	if(c->page_frame==NULL)
 	{
@@ -1124,64 +1127,71 @@
 	 *	Now we need the Hardware Resource Table. We must ask for
 	 *	this next we can't issue random messages yet.
 	 */
+	ret=i2o_hrt_get(c);
+	if(ret)
+		return ret;
+
+	ret=i2o_parse_hrt(c);
+	if(ret)
+		return ret;
+
+	return i2o_online_controller(c);
+//	i2o_report_controller_unit(c, ADAPTER_TID);
+}
 
 
-	workspace=kmalloc(2048, GFP_KERNEL);
-	if(workspace==NULL)
+int i2o_lct_get(struct i2o_controller *c)
+{
+	u32 m;
+	u32 *msg;
+
+	m=i2o_wait_message(c, "LCTNotify");
+
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;
+
+	msg=(u32 *)(c->mem_offset+m);
+
+	c->lct = kmalloc(8192, GFP_KERNEL);
+	if(c->lct==NULL)
 	{
-		printk(KERN_ERR "IOP init failed; no memory.\n");
+		msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1]= HOST_TID<<12|ADAPTER_TID;	/* NOP */
+		i2o_post_message(c,m);
+		printk(KERN_ERR "No free memory for i2o controller buffer.\n");
 		return -ENOMEM;
 	}
 	
-	m=i2o_wait_message(c, "I2O HRT timeout.");
-	if(m==0xFFFFFFFF)
-	{	
-		kfree(workspace);
-		return -ETIMEDOUT;
-	}
+	memset(c->lct, 0, 8192);
 	
-	msg=(u32 *)(c->mem_offset+m);
+	msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+	msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2] = 0;		/* Context not needed */
+	msg[3] = 0;
+	msg[4] = 0xFFFFFFFF;	/* All devices */
+	msg[5] = 0x00000000;	/* Report now */
+	msg[6] = 0xD0000000|8192;
+	msg[7] = virt_to_bus(c->lct);
 
-	msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
-	msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2]= 0x0;
-	msg[3]= 0x0;				/* Transaction context */
-	msg[4]= (0xD0000000 | 2048);		/* Simple transaction , 2K */
-	msg[5]= virt_to_phys(workspace);	/* Dump it here */
-	*((u32 *)workspace)=0xFFFFFFFF;
-	
 	i2o_post_message(c,m);
-	
+
 	barrier();
-	
-	/*
-	 *	Now wait for a reply
-	 */
-	 
-	m=i2o_wait_reply(c, "HRT table", 5);
-	 
+
+	/* Now wait for a reply */
+	m=i2o_wait_reply(c, "LCTNotify", 5);
+
 	if(m==0xFFFFFFFF)
-	{
-		kfree(workspace);
 		return -ETIMEDOUT;
-	}
-	
+
 	msg=(u32 *)bus_to_virt(m);
-	
+
+	/* TODO: Check TableSize for big LCTs and send new ExecLctNotify 
+	 * with bigger workspace */
+
 	if(msg[4]>>24)
-	{
-		i2o_report_status(KERN_WARNING, "i2o_core",
-				  (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-				  msg[4]&0xFFFF);
-	}
-	I2O_REPLY_WRITE32(c,m);
-	
-	i2o_parse_hrt(c, workspace);
-	
-	kfree(workspace);
-	
-	return i2o_online_controller(c);
-//	i2o_report_controller_unit(c, ADAPTER_TID);
+		i2o_report_status(KERN_ERR, "i2o_core", msg);
+
+	return 0;
 }
 
 
@@ -1196,7 +1206,7 @@
 	u32 systab[32];
 	u32 privmem[2];
 	u32 privio[2];
-	u32 *workspace;
+	int ret;
 	
 	systab[0]=1;
 	systab[1]=0;
@@ -1216,7 +1226,7 @@
 	privio[0]=c->priv_io;		/* Private I/O address */
 	privio[1]=c->priv_io_size;
 	
-	m=i2o_wait_message(c, "SetSysTab");
+	m=i2o_wait_message(c, "SysTabSet");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
 	
@@ -1249,7 +1259,7 @@
 	 */
 	 
 	 
-	m=i2o_wait_reply(c, "Systab read", 5);
+	m=i2o_wait_reply(c, "SysTabSet", 5);
 		
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
@@ -1258,9 +1268,7 @@
 	
 	if(msg[4]>>24)
 	{
-		i2o_report_status(KERN_ERR, "i2o_core",
-				  (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-				  msg[4]&0xFFFF);
+		i2o_report_status(KERN_ERR, "i2o_core", msg);
 	}
 	I2O_REPLY_WRITE32(c,m);
 	
@@ -1268,7 +1276,7 @@
 	 *	Finally we go online
 	 */
 	 
-	m=i2o_wait_message(c, "No message for SysEnable");
+	m=i2o_wait_message(c, "SysEnable");
 	
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
@@ -1289,7 +1297,7 @@
 	 */
 	 
 	
-	m=i2o_wait_reply(c, "Enable", 240);
+	m=i2o_wait_reply(c, "SysEnable", 240);
 
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
@@ -1298,73 +1306,25 @@
 	
 	if(msg[4]>>24)
 	{
-		i2o_report_status(KERN_ERR, "i2o_core",
-				  (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-				  msg[4]&0xFFFF);
+		i2o_report_status(KERN_ERR, "i2o_core", msg);
 	}
 	I2O_REPLY_WRITE32(c,m);
 	
 	/*
 	 *	Grab the LCT, see what is attached
 	 */
-	 
-	m=i2o_wait_message(c, "No message for LCT");
-	
-	if(m==0xFFFFFFFF)
-		return -ETIMEDOUT;
-	
-	msg=(u32 *)(c->mem_offset+m);
-	
-	
-	workspace = kmalloc(8192, GFP_KERNEL);
-	if(workspace==NULL)
-	{
-		msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
-		msg[1]= HOST_TID<<12|ADAPTER_TID;	/* NOP */
-		i2o_post_message(c,m);
-		printk(KERN_ERR "No free memory for i2o controller buffer.\n");
-		return -ENOMEM;
-	}
-	
-	memset(workspace, 0, 8192);
-	
-	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6;
-	msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
-	msg[2] = 0;		/* Context not needed */
-	msg[3] = 0;
-	msg[4] = 0xFFFFFFFF;	/* All devices */
-	msg[5] = 0x00000000;	/* Report now */
-	msg[6] = 0xD0000000|8192;
-	msg[7] = virt_to_bus(workspace);
-	
-	i2o_post_message(c,m);
-	
-	barrier();
 
-	/*
-	 *	Now wait for a reply
-	 */
-	 
-	m=i2o_wait_reply(c, "LCT", 5);
-	
-	if(m==0xFFFFFFFF)
+	ret=i2o_lct_get(c);
+	if(ret)
 	{
-		kfree(workspace);
-		return -ETIMEDOUT;
+		/* Maybe we should do also sthg else */
+		return ret;
 	}
-	
-	msg=(u32 *)bus_to_virt(m);
-	
-	if(msg[4]>>24)
-	{
-		i2o_report_status(KERN_ERR, "i2o_core",
-				  (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF,
-				  msg[4]&0xFFFF);
-	}
-	
-	i2o_parse_lct(c, workspace);
-	kfree(workspace);
-	
+
+	ret=i2o_parse_lct(c);
+	if(ret)
+		return ret;
+
 	I2O_REPLY_WRITE32(c,m);
 	
 	return 0;
@@ -1417,16 +1377,21 @@
 	*flag = 0;
 		
 	if(i2o_post_this(c, tid, data, len))
-		return -1;
+		return I2O_POST_WAIT_TIMEOUT;
 		
 	while(!*flag && (jiffies-t)<timeout*HZ)
 	{
 		schedule();
 		mb();
 	}
-	if(*flag <= 0)
-		return -1;
-	return 0;
+
+	if (*flag < 0)
+		return *flag; /* DetailedStatus */
+
+	if (*flag == 0)
+		return I2O_POST_WAIT_TIMEOUT;
+	
+	return I2O_POST_WAIT_OK;
 }
 
 /*
@@ -1452,247 +1417,262 @@
 	return i2o_post_wait(c, tid, msg, 20, flag,2);
 }
 
+/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *	This function can be used for all UtilParamsGet/Set operations.
+ *	The OperationBlock is given in opblk-buffer, 
+ *	and results are returned in resblk-buffer.
+ *	Note that the minimum sized resblk is 8 bytes and contains
+ *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
+ */
+int i2o_issue_params(int cmd, 
+                struct i2o_controller *iop, int tid, int context, 
+                void *opblk, int oplen, void *resblk, int reslen, 
+                int *flag)
+{
+        u32 msg[9]; 
+	u8 *res = (u8 *)resblk;
+	int res_count;
+	int blk_size;
+	int bytes;
+	int wait_status;
+
+        msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
+        msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
+        msg[2] = context | 0x80000000;
+        msg[3] = (u32)flag;
+        msg[4] = 0;
+        msg[5] = 0x54000000 | oplen;	/* OperationBlock */
+        msg[6] = virt_to_bus(opblk);
+        msg[7] = 0xD0000000 | reslen;	/* ResultBlock */
+        msg[8] = virt_to_bus(resblk);
+
+        wait_status = i2o_post_wait(iop, tid, msg, sizeof(msg), flag, 10);
+	if (wait_status < 0)       
+                return wait_status; 	/* -DetailedStatus */
+
+        if (res[1]&0x00FF0000) 	/* BlockStatus != SUCCESS */
+        {
+                printk(KERN_WARNING "%s - Error:\n  ErrorInfoSize = 0x%02x, " 
+                	"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+                        (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+                                                         : "PARAMS_GET",   
+                        res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
+                return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+        }
+
+    	res_count = res[0] & 0xFFFF; /* # of resultblocks */
+    	bytes = 4; 
+    	res  += 4;
+    	while (res_count--)
+	{
+		blk_size = (res[0] & 0xFFFF) << 2;
+		bytes   += blk_size;
+		res     += blk_size;
+	}
+
+        return bytes; /* total sizeof Result List in bytes */
+}
+
+/*
+ *	 Query one scalar group value or a whole scalar group.
+ */                  	
+int i2o_query_scalar(struct i2o_controller *iop, int tid, int context, 
+                     int group, int field, void *buf, int buflen, int *flag)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
+	u8  resblk[8+buflen]; /* 8 bytes for header */
+	int size;
+
+	if (field == -1)  		/* whole group */
+       		opblk[4] = -1;
+              
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, context, 
+			opblk, sizeof(opblk), resblk, sizeof(resblk), flag);
+			
+	if (size < 0)
+		return size;	
+
+	memcpy(buf, resblk+8, buflen);  /* cut off header */
+	return buflen;
+}
+
 /*
- *	Query a scalar value
+ *	Set a scalar group value or a whole group.
  */
-
-int i2o_query_scalar(struct i2o_controller *c, int tid, int context,
-		     int group, int field, void *buf, int buflen, int *flag)
+int i2o_set_scalar(struct i2o_controller *iop, int tid, int context, 
+		   int group, int field, void *buf, int buflen, int *flag)
 {
-	u16 *op;
-	u32 *bl;
-	u32 msg[9];
-
-	bl=kmalloc(buflen+64, GFP_KERNEL); /* Enough space for error replys */
-	if(bl==NULL)
-	{
-		printk(KERN_ERR "i2o: no memory for query buffer.\n");
-		return -ENOMEM;
-	}
-
-	op = (u16*)bl;
-	op[0]=1;			/* One Operation */
-	op[1]=0;			/* PAD */
-	op[2]=1;			/* FIELD_GET */
-	op[3]=group;			/* group number */
-	op[4]=1;			/* field count, default = 1 */
-	op[5]=field;			/* field index */
+	u16 *opblk;
+	u8  resblk[8+buflen]; /* 8 bytes for header */
+        int size;
+
+        opblk = kmalloc(buflen+64, GFP_KERNEL);
+        if (opblk == NULL)
+        {
+                printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+                return -ENOMEM;
+        }
+
+        opblk[0] = 1;                        /* operation count */
+        opblk[1] = 0;                        /* pad */
+        opblk[2] = I2O_PARAMS_FIELD_SET;
+        opblk[3] = group;
+
+        if(field == -1) {               /* whole group */
+                opblk[4] = -1;
+                memcpy(opblk+5, buf, buflen);
+        }
+        else                            /* single field */
+        {
+                opblk[4] = 1;
+                opblk[5] = field;
+                memcpy(opblk+6, buf, buflen);
+        }   
 
-	if(field == -1)
-	/* Single value or the whole group? */
-	{
-		op[4]=-1;
-		op[5]=0;
-	}
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+			opblk, 12+buflen, resblk, sizeof(resblk), flag);
 
-	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-	msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid;
-	msg[2]=context|0x80000000;	/* So we can pick it out */
-	msg[3]=(u32)flag;
-	msg[4]=0;
-	msg[5]=0x54000000|12;
-	msg[6]=virt_to_bus(bl);
-		/*
-		 *	There are 8 bytes of "overhead" required to pull in
-		 *	a Params ResultsList; 2 bytes for ResultCount
-		 *	(which should have value=1), plus 2 bytes for pad,
-		 *	plus 2 bytes for BlockSize, plus 1 byte BlockStatus,
-		 *	plus 1 byte ErrorInfoSize (8 bytes total overhead).
-		 *	This is followed finally by actual result value(s).
-		 *
-		 *	Tell the IOP to return 8 + buflen bytes.
-		 */
-	msg[7]=0xD0000000|(8+buflen);
-	msg[8]=virt_to_bus(bl+3);
-	
-	bl[3]=0xFCFCFCFC;		// Pad,ResultCount
-	bl[4]=0xFAFAFCFC;		// ErrorInfoSize,BlockStatus,BlockSize
-
-	/*
-	 *	Post the message and await a reply
-	 */
-
-	if (i2o_post_wait(c, tid, msg, sizeof(msg), flag,2) < 0)
-	{
-		kfree(bl);		
-		return -1;
-	}
-
-	if(bl[4]&0x00FF00000) /* BlockStatus != SUCCESS */
-	{
-		printk(KERN_WARNING "i2o_query_scalar - Error\n"
-			"ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, "
-			"BlockSize = 0x%04x\n", 
-			bl[4]>>24, (bl[4]>>16)&0xFF, bl[4]&0xFFFF);
-		kfree(bl);
-		return -1;
-	}
-	if((bl[3] & 0xFFFF) != 1)
-	{
-		printk(KERN_ERR "i2o: query ResultCount = 0x%04x\n", bl[3]&0xFFFF);
-	}
-	
-	memcpy(buf, bl+5, buflen);
-	kfree(bl);
-	return 0;
+	kfree(opblk);
+	return size;
 }
 
-
-#if 0
 /* 
- * Query a table field 
- * FIXME: NOT TESTED! 
+ * 	if oper == I2O_PARAMS_TABLE_GET: 
+ *		Get all table group fields from all rows or
+ *		get specific table group fields from all rows.
+ *
+ * 		if fieldcount == -1 we query all fields from all rows
+ *			ibuf is NULL and ibuflen is 0
+ * 		else we query specific fields from all rows
+ *  			ibuf contains fieldindexes
+ *
+ * 	if oper == I2O_PARAMS_LIST_GET:
+ *		Get all table group fields from specified rows or
+ *		get specific table group fields from specified rows.
+ *
+ * 		if fieldcount == -1 we query all fields from specified rows
+ *			ibuf contains rowcount, keyvalues
+ * 		else we query specific fields from specified rows
+ *  			ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ *	You could also use directly function i2o_issue_params().
  */
-int i2o_query_table(struct i2o_controller *c, int tid, int context,
-		    void *buf, int buflen,
-		    int table,
-		    int *field, int fieldlen,
-		    u32 *key, int keylen,
-		    int *flag)
+int i2o_query_table(int oper,
+		struct i2o_controller *iop, int tid, int context, int group,
+		int fieldcount, void *ibuf, int ibuflen,
+		void *resblk, int reslen, int *flag) 
 {
-	static u16 op[32];
-	u32 *bl;
-	u32 msg[9];
-	int i;
+	u16 *opblk;
+	int size;
 
-	bl=kmalloc(buflen+64, GFP_KERNEL);
-	if(bl==NULL)
+	opblk = kmalloc(10 + ibuflen, GFP_KERNEL);
+	if (opblk == NULL)
 	{
 		printk(KERN_ERR "i2o: no memory for query buffer.\n");
 		return -ENOMEM;
 	}
 
-	op[0]=1;			/* Operation count */
-	op[1]=0;			/* Reserved */
-	op[2]=I2O_PARAMS_LIST_GET;	/* Operation */
-	op[3]=table;			/* Group */
-	/* Specific fields or the whole group? */
-	if(*field != -1)
-	{ /* FIXME: Fields can be variable size */
-		op[4]=fieldlen;
-		for (i=0; i < fieldlen; i++)
-			op[4+i]=field[i];
-	}
-	else
-	{
-		op[4]=-1;
-		op[5]=0;
-	}
-
-	memcpy(bl, op, 12);
-	       	
-	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-	msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid;
-	msg[2]=context|0x80000000;	/* So we can pick it out */
-	msg[3]=(u32)flag;
-	msg[4]=0;
-	msg[5]=0x54000000|12;
-	msg[6]=virt_to_bus(bl);
+	opblk[0] = 1;				/* operation count */
+	opblk[1] = 0;				/* pad */
+	opblk[2] = oper;
+	opblk[3] = group;		
+	opblk[4] = fieldcount;
+	memcpy(opblk+5, ibuf, ibuflen);		/* other params */
 
-	msg[7]=0xD0000000|(buflen+48);
-	msg[8]=virt_to_bus(bl+4);
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, context, 
+			opblk, 10+ibuflen, resblk, reslen, flag);
 
-	/*
-	 *	Post the message and await a reply
-	 */
+	kfree(opblk);
+	return size;
+}
 
-	if(i2o_post_wait(c, tid, msg, sizeof(msg), flag,2)<0)
-		return -1;
-	
-	if(bl[5]&0x00FF00000)	/* BlockStatus != SUCCESS */
-	{
-		printk(KERN_WARNING "i2o_query_table - Error\n"
-			"ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, "
-			"BlockSize = 0x%04x\n", 
-			bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF);
-		kfree(bl);
-		return -1;
-	}
+/*
+ * 	Clear table group, i.e. delete all rows.
+ */
 
-	if((bl[4]&0xFFFF)!=1)
-		printk(KERN_ERR "i2o: query ResultCount = %0#4x\n",
-		       bl[4]&0xFFFF);
+int i2o_clear_table(struct i2o_controller *iop, int tid, int context,
+		    int group, int *flag)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
+	u8  resblk[32]; /* min 8 bytes for result header */
 
-	memcpy(buf, bl+6, buflen);
-	kfree(bl);
-	return 0;
+        return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+			opblk, sizeof(opblk), resblk, sizeof(resblk), flag);
 }
-#endif
 
 /*
- * Set (for now) scalar value
+ * 	Add a new row into a table group.
  *
- * TODO: Add support for table groups
- */
+ * 	if fieldcount==-1 then we add whole rows
+ *		buf contains rowcount, keyvalues
+ * 	else just specific fields are given, rest use defaults
+ *  		buf contains fieldindexes, rowcount, keyvalues
+ */	
 
-int i2o_params_set(struct i2o_controller *c, int tid, int context, int table,
-		   int field, void *buf, int buflen, int *flag)
+int i2o_row_add_table(struct i2o_controller *iop, int tid, int context,
+		    int group, int fieldcount, void *buf, int buflen,
+		    int *flag)
 {
-	static u16 opdata[]={1,0,6,0,1,4,0};
-	u32 *bl;
-	u32 msg[9];
+	u16 *opblk;
+	u8  resblk[32]; /* min 8 bytes for header */
+	int size;
 
-	bl=kmalloc(buflen+64, GFP_KERNEL);
-	if(bl==NULL)
+	opblk = kmalloc(buflen+64, GFP_KERNEL);
+	if (opblk == NULL)
 	{
-		printk(KERN_ERR "i2o: no memory for set buffer.\n");
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
 		return -ENOMEM;
 	}
 
-	opdata[3]=table;
-	/* Single value or the whole group? */
-	if(field != -1) {
-		opdata[4]=1;	
-		opdata[5]=field;
-		opdata[6]=*(u16 *)buf;
-	}
-	else {
-		opdata[4]=-1;
-		opdata[5]=0;
-	}
+	opblk[0] = 1;			/* operation count */
+	opblk[1] = 0;			/* pad */
+	opblk[2] = I2O_PARAMS_ROW_ADD;
+	opblk[3] = group;	
+	opblk[4] = fieldcount;
+	memcpy(opblk+5, buf, buflen);
 
-	memcpy(bl, opdata, 14);
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+			opblk, 10+buflen, resblk, sizeof(resblk), flag);
 
-	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-	msg[1]=I2O_CMD_UTIL_PARAMS_SET<<24|HOST_TID<<12|tid;
-	msg[2]=context|0x80000000;	/* So we can pick it out */
-	msg[3]=(u32)flag;
-	msg[4]=0;
-	msg[5]=0x54000000|14;
-	msg[6]=virt_to_bus(bl);
-	msg[7]=0xD0000000|(buflen+48);
-	msg[8]=virt_to_bus(bl+4);
-	
-	/* Post the message and wait for a reply */
-	if(i2o_post_wait(c, tid, msg, 36, flag, 5)<0)
-	{
-		kfree(bl);
-		return -1;
-	}
+	kfree(opblk);
+	return size;
+}
 
-	/* Perhaps we should check errors, eh? */
-	if(bl[5]&0x00FF00000)	/* BlockStatus != SUCCESS */
-	{
-		printk(KERN_WARNING "i2o_params_set - Error\n"
-			"ErrorInfoSize = %0#2x, BlockStatus = %0#2x, "
-			"BlockSize = %0#4x\n", 
-			bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF);
-		kfree(bl);
-		return -1;
-	}
+/*
+ *	Delete rows from a table group.
+ */ 
+
+int i2o_row_delete_table(struct i2o_controller *iop, int tid, int context,
+		    int group, int keycount, void *keys, int keyslen,
+		    int *flag)
+{
+	u16 *opblk; 
+	u8  resblk[32]; /* min 8 bytes for header */
+	int size;
 
-	if((bl[4] & 0xFFFF) != 1)
+	opblk = kmalloc(keyslen+64, GFP_KERNEL);
+	if (opblk == NULL)
 	{
-		printk(KERN_ERR "i2o: params set ResultCount = %0#4x\n",
-		       bl[4]&0xFFFF);
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+		return -ENOMEM;
 	}
 
-	kfree(bl);
-	return 0;
-}
+	opblk[0] = 1;			/* operation count */
+	opblk[1] = 0;			/* pad */
+	opblk[2] = I2O_PARAMS_ROW_DELETE;
+	opblk[3] = group;	
+	opblk[4] = keycount;
+	memcpy(opblk+5, keys, keyslen);
 
+        size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, 
+			opblk, 10+keyslen, resblk, sizeof(resblk), flag);
+
+	kfree(opblk);
+	return size;
+}
 
-void report_common_status(u8 req_status)
+void i2o_report_common_status(u8 req_status)
 {
 	/* the following reply status strings are common to all classes */
 
@@ -1719,7 +1699,7 @@
 	return;
 }
 
-static void report_common_dsc(u16 detailed_status)
+static void i2o_report_common_dsc(u16 detailed_status)
 {
 	/* The following detailed statuscodes are valid 
 	   - for executive class, utility class, DDM class and
@@ -1766,7 +1746,7 @@
 	return;
 }
 
-void report_lan_dsc(u16 detailed_status)
+static void i2o_report_lan_dsc(u16 detailed_status)
 {
 	static char *LAN_DSC[] = {	// Lan detailed status code strings
 		"SUCCESS",
@@ -1786,10 +1766,11 @@
 		"DEST_ADDRESS_DETECTED",
 		"DEST_ADDRESS_OMITTED",
 		"PARTIAL_PACKET_RETURNED",
-		"TEMP_SUSPENDED_STATE"
+		"TEMP_SUSPENDED_STATE",	// last Lan detailed status code
+		"INVALID_REQUEST"	// general detailed status code
 	};
 
-	if (detailed_status > I2O_LAN_DSC_TEMP_SUSPENDED_STATE)
+	if (detailed_status > I2O_DSC_INVALID_REQUEST)
 		printk("%0#4x.\n", detailed_status);
 	else
 		printk("%s.\n", LAN_DSC[detailed_status]);
@@ -1797,7 +1778,7 @@
 	return;	
 }
 
-static void report_util_cmd(u8 cmd)
+static void i2o_report_util_cmd(u8 cmd)
 {
 	switch (cmd) {
 	case I2O_CMD_UTIL_NOP:
@@ -1850,7 +1831,7 @@
 }
 
 
-static void report_exec_cmd(u8 cmd)
+static void i2o_report_exec_cmd(u8 cmd)
 {
 	switch (cmd) {
 	case I2O_CMD_ADAPTER_ASSIGN:
@@ -1959,7 +1940,7 @@
 	return;	
 }
 
-static void report_lan_cmd(u8 cmd)
+static void i2o_report_lan_cmd(u8 cmd)
 {
 	switch (cmd) {
 	case LAN_PACKET_SEND:
@@ -1985,30 +1966,32 @@
 }
 
 /* TODO: Add support for other classes */
-void i2o_report_status(const char *severity, const char *module, u8 cmd,
-		       u8 req_status, u16 detailed_status)
+void i2o_report_status(const char *severity, const char *module, u32 *msg)
 {
-	printk("%s", severity);
-	printk("%s: ", module);
+	u8 cmd = (msg[1]>>24)&0xFF;
+	u8 req_status = (msg[4]>>24)&0xFF;
+	u16 detailed_status = msg[4]&0xFFFF;
+
+	printk("%s%s: ", severity, module);
 
 	if (cmd < 0x1F) { 			// Utility Class
-		report_util_cmd(cmd);
-		report_common_status(req_status);
-		report_common_dsc(detailed_status);
+		i2o_report_util_cmd(cmd);
+		i2o_report_common_status(req_status);
+		i2o_report_common_dsc(detailed_status);
 		return;
 	}
 
 	if (cmd >= 0x30 && cmd <= 0x3F) {	// LAN class
-		report_lan_cmd(cmd);
-		report_common_status(req_status);		
-		report_lan_dsc(detailed_status);
+		i2o_report_lan_cmd(cmd);
+		i2o_report_common_status(req_status);		
+		i2o_report_lan_dsc(detailed_status);
 		return;
 	}
 	
 	if (cmd >= 0xA0 && cmd <= 0xEF) {	// Executive class
-		report_exec_cmd(cmd);
-		report_common_status(req_status);
-		report_common_dsc(detailed_status);
+		i2o_report_exec_cmd(cmd);
+		i2o_report_common_status(req_status);
+		i2o_report_common_dsc(detailed_status);
 		return;
 	}
 	
@@ -2017,6 +2000,8 @@
 }
 
 
+#ifdef CONFIG_MODULE
+
 EXPORT_SYMBOL(i2o_install_handler);
 EXPORT_SYMBOL(i2o_remove_handler);
 EXPORT_SYMBOL(i2o_install_device);
@@ -2037,16 +2022,75 @@
 EXPORT_SYMBOL(i2o_get_class_name);
 
 EXPORT_SYMBOL(i2o_query_scalar);
-EXPORT_SYMBOL(i2o_params_set);
+EXPORT_SYMBOL(i2o_set_scalar);
+EXPORT_SYMBOL(i2o_query_table);
+EXPORT_SYMBOL(i2o_clear_table);
+EXPORT_SYMBOL(i2o_row_add_table);
+EXPORT_SYMBOL(i2o_row_delete_table);
+
 EXPORT_SYMBOL(i2o_post_this);
 EXPORT_SYMBOL(i2o_post_wait);
 EXPORT_SYMBOL(i2o_issue_claim);
 
 EXPORT_SYMBOL(i2o_report_status);
-EXPORT_SYMBOL(report_common_status);
-EXPORT_SYMBOL(report_lan_dsc);
-
-EXPORT_SYMBOL(i2o_wait_message);
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
+
+
+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;
+        }
+
+        core_context = i2o_core_handler.context;
+
+        return 0;
+}
+
+void cleanup_module(void)
+{
+	i2o_remove_handler(&i2o_core_handler);
+}
+
+#else
+
+extern int i2o_block_init(void);
+extern int i2o_config_init(void);
+extern int i2o_lan_init(void);
+extern int i2o_pci_init(void);
+extern int i2o_proc_init(void);
+extern int i2o_scsi_init(void);
+
+__init int i2o_init(void)
+{
+        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;
+#ifdef CONFIG_I2O_PCI
+	i2o_pci_init();
+#endif
+	i2o_config_init();
+#ifdef CONFIG_I2O_BLOCK
+	i2o_block_init();
+#endif
+#ifdef CONFIG_I2O_SCSI
+	i2o_scsi_init();
+#endif
+#ifdef CONFIG_I2O_LAN
+	i2o_lan_init();
+#endif
+#ifdef CONFIG_I2O_PROC
+	i2o_proc_init();
+#endif
+	return 0;
+}
+
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.9/linux/drivers/i2o/i2o_lan.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/i2o/i2o_lan.c	Mon Jul  5 20:09:40 1999
@@ -1,7 +1,7 @@
 /*
  * 	linux/drivers/i2o/i2o_lan.c
  *
- *    	I2O LAN CLASS OSM 	Prototyping, May 7th 1999
+ *    	I2O LAN CLASS OSM 	Prototyping, June 4th 1999
  *
  *	(C) Copyright 1999 	University of Helsinki,
  *				Department of Computer Science
@@ -13,16 +13,19 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.    
  *
- * 	Author: 	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * 	Authors: 	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
  *
  *	Tested:		in FDDI environment (using SysKonnect's DDM)
- *			in ETH environment (using Intel 82558 DDM proto)
+ *			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
+ *			- 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
  */
 
 #include <linux/config.h>
@@ -35,6 +38,7 @@
 #include <linux/if_arp.h>
 #include <linux/malloc.h>
 #include <linux/trdevice.h>
+#include <linux/init.h>
 #include <asm/io.h>
 
 #include <linux/errno.h>
@@ -56,9 +60,9 @@
 struct i2o_lan_local {
 	u8 unit;
 	struct i2o_device *i2o_dev;
-	int reply_flag; 		// needed by scalar/table queries
-	struct fddi_statistics stats;
-/*	first fields are same as in struct net_device_stats stats; */ 
+	int reply_flag; 		/* needed by scalar/table queries */
+	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 *);
 };
 
@@ -66,6 +70,11 @@
 static int i2o_lan_receive_post(struct device *dev);
 static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m);
 
+/*
+ * Module params
+ */
+static u32 bucketpost = 64;
+static u32 bucketthresh = 8;
 
 static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, 
 			  struct i2o_message *m)
@@ -74,17 +83,25 @@
 	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
 	struct device *dev = i2o_landevs[unit];
 
-#ifdef DRIVERDEBUG
-	i2o_report_status(KERN_INFO, "i2o_lan", msg[1]>>24, msg[4]>>24,
-			  msg[4]&0xFFFF);
-#endif
     	if (msg[0] & (1<<13)) // Fail bit is set
  	{
- 		printk(KERN_INFO "IOP failed to process the msg\n");
-		printk("From tid=%d to tid=%d",(msg[1]>>12)&0xFFF,msg[1]&0xFFF);
+ 		printk(KERN_ERR "IOP failed to process the msg:\n");
+		printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid = %d\n",
+			(msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
+		printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n  "
+			"LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+			 msg[4] >> 24, (msg[4] >> 16) & 0xFF, 
+			(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+		printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+			msg[5] >> 16, msg[5] & 0xFFF);
 		return;
 	}	
 
+#ifdef DRIVERDEBUG
+//	if (msg[4] >> 24) 	/* ReqStatus != SUCCESS */
+		i2o_report_status(KERN_INFO, "i2o_lan", msg);
+#endif
+
 	switch (msg[1] >> 24) {
 	case LAN_RECEIVE_POST: 
 		if (dev->start) 
@@ -94,11 +111,9 @@
 			u8 trl_count  = msg[3] & 0x000000FF; 	
 			struct i2o_bucket_descriptor *bucket =
 				(struct i2o_bucket_descriptor *)&msg[6];
-			struct sk_buff *skb;
 			do {	
-				dprintk("Releasing unused bucket\n");
-				skb = (struct sk_buff *)bucket->context;
-				dev_kfree_skb(skb);
+				dprintk("%s: Releasing unused bucket\n",dev->name);
+				dev_kfree_skb((struct sk_buff *)bucket->context);
 				bucket++;
 			} while (--trl_count);
 		}			
@@ -110,30 +125,30 @@
 		u8 trl_count  = msg[3] & 0x000000FF; 	
 		
 		if (msg[4] >> 24) 	// ReqStatus != SUCCESS
-		{
-			printk(KERN_WARNING "%s: ",dev->name); 
-			report_common_status(msg[4]>>24);
-			report_lan_dsc(msg[4]&0xFFFF);
-		}
+			i2o_report_status(KERN_WARNING, dev->name, msg);
 
-		do {	// The HDM has handled the outgoing packet
+		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",
 				dev->name,trl_count);
 		} while (--trl_count);
 		
-			dev->tbusy = 0;
-			mark_bh(NET_BH); /* inform upper layers */
+		dev->tbusy = 0;
+		mark_bh(NET_BH); /* inform upper layers */
 	}
 	break;	
 
 	default: 
-		if (msg[2] & 0x80000000)  	// reply to a util get/set
-		{	// flag for the i2o_post_wait
-	       		int *flag = (int *)msg[3];
-	       		// ReqStatus != I2O_REPLY_STATUS_SUCCESS
-	      		 *flag = (msg[4] >> 24) ? I2O_POST_WAIT_TIMEOUT 
-	       				        : I2O_POST_WAIT_OK ;
+		if (msg[2] & 0x80000000)  // reply to a UtilParamsGet/Set
+		{	
+	       		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;
 		}
 	}
 }
@@ -155,40 +170,54 @@
 	struct i2o_packet_info *packet;
 	
 	u8 trl_count  = msg[3] & 0x000000FF; 	
-	struct sk_buff *skb;
+	struct sk_buff *skb, *newskb;
 
-#ifdef 0
+#if 0
 	dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n"
 		"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]);
 
-/* 
- * NOTE: here we assume that also in batch mode we will get only 
- * one packet per bucket. This can be ensured by setting the 
- * PacketOrphanLimit to MaxPacketSize, as well as the bucket size.
- */
 	do {
-		/* packet is not at all needed here */
+		skb = (struct sk_buff *)(bucket->context);		
 		packet = (struct i2o_packet_info *)bucket->packet_info;	
-#ifdef 0
+#if 0
 		dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
 			packet->flags, packet->offset, packet->status, packet->len);
 #endif
-		skb = (struct sk_buff *)(bucket->context);
-		skb_put(skb,packet->len);
-		skb->dev  = dev;		
-		skb->protocol = priv->type_trans(skb, dev);
-		netif_rx(skb);
+		if (packet->len < priv->packet_tresh) {
+			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);
+				newskb->dev = dev;
+				newskb->protocol = priv->type_trans(newskb, dev);
 
+				netif_rx(newskb);
+				dev_kfree_skb(skb); // FIXME: reuse this skb? 
+			}
+			else {
+				printk("Can't allocate skb.\n");
+				return -ENOMEM;
+			}
+		} else {
+			skb_put(skb,packet->len);		
+			skb->dev  = dev;		
+			skb->protocol = priv->type_trans(skb, dev);
+
+			netif_rx(skb);
+		}
 		dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
 			"to upper level.\n",dev->name,packet->len);
-			
-		bucket++; // to next Packet Descriptor Block
 
+		bucket++; // to next Packet Descriptor Block
 	} while (--trl_count);
 
-	if (msg[5] <= I2O_BUCKET_THRESH)  	// BucketsRemaining
+
+	if (msg[5] <= bucketthresh)  	// BucketsRemaining
 		i2o_lan_receive_post(dev);
 
 	return 0;
@@ -198,6 +227,7 @@
  *  Interface to i2o:  functions to send lan class request 
  */
 
+
 /* 
  * i2o_lan_receive_post(): Post buckets to receive packets.
  */
@@ -211,25 +241,22 @@
 	
 	u32 bucket_len = (dev->mtu + dev->hard_header_len);
 	u32 bucket_count;
-	int n_elems = (iop->inbound_size - 16 ) / 12; // msg header + SGLs
+	int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */
 	u32 total = 0;
 	int i;
 
-	dprintk(KERN_INFO "%s: Allocating %d buckets (size %d).\n", 
-		dev->name, I2O_BUCKET_COUNT, bucket_len);
-
-	while (total < I2O_BUCKET_COUNT)
+	while (total < bucketpost)
 	{
 		m = I2O_POST_READ32(iop);
 		if (m == 0xFFFFFFFF)
 			return -ETIMEDOUT;		
 		msg = bus_to_virt(iop->mem_offset + m);
 	
-		bucket_count = (total + n_elems < I2O_BUCKET_COUNT)
+		bucket_count = (total + n_elems < bucketpost)
 			     ? n_elems
-			     : I2O_BUCKET_COUNT - total;
-			     
-		msg[0] = I2O_MESSAGE_SIZE(4 + 3 *  bucket_count) | 1<<12 | SGL_OFFSET_4;
+			     : bucketpost - total;
+
+		msg[0] = I2O_MESSAGE_SIZE(4 + 3 *  bucket_count) | SGL_OFFSET_4;
 		msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->id;
 		msg[2] = priv->unit << 16 | lan_context; // InitiatorContext	
 		msg[3] = bucket_count;			 // BucketCount
@@ -248,7 +275,7 @@
 		i2o_post_message(iop,m);
 
 		dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
-			dev->name,bucket_count,bucket_len);
+			dev->name, bucket_count, bucket_len);
 
 		total += bucket_count;
 	}
@@ -264,12 +291,7 @@
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;	
-	u32 m; u32 *msg;
-
-	m = I2O_POST_READ32(iop);
-	if (m == 0xFFFFFFFF)
-		return -ETIMEDOUT;
-	msg = bus_to_virt(iop->mem_offset + m);
+	u32 msg[5];
 
 	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
 	msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->id;
@@ -277,7 +299,8 @@
 	msg[3] = 0; 				 // TransactionContext
 	msg[4] = 1 << 16; 			 // return posted buckets
 
-	i2o_post_message(iop,m);
+	if (i2o_post_this(iop, i2o_dev->id, msg, sizeof(msg)) < 0)
+		return -ETIMEDOUT;		
 
 	return 0; 
 }
@@ -292,12 +315,7 @@
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;	
-	u32 m; u32 *msg;
-
-	m = I2O_POST_READ32(iop);
-	if (m == 0xFFFFFFFF)
-		return -ETIMEDOUT;
-	msg = bus_to_virt(iop->mem_offset + m);
+	u32 msg[5];
 
 	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
 	msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->id;
@@ -305,7 +323,8 @@
 	msg[3] = 0; 				 // TransactionContext
 	msg[4] = 1 << 16; 			 // return posted buckets
 
-	i2o_post_message(iop,m);
+	if (i2o_post_this(iop, i2o_dev->id, msg, sizeof(msg)) < 0)
+		return -ETIMEDOUT;
 
 	return 0;
 }
@@ -330,12 +349,13 @@
 
 	// enable batch mode, toggle automatically
 	val = 0x00000000;
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 0,
+//	val = 0x00000001; // turn off batch mode
+	if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0003, 0,
 			&val, 4, &priv->reply_flag) <0)
 		printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n");
 	else
 		dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name);
-
+//		dprintk(KERN_INFO "%s: I2O LAN batch mode disabled.\n",dev->name);
 	/*
 	 * When PacketOrphanlimit is same as the maximum packet length,
 	 * the packets will never be split into two separate buckets
@@ -344,46 +364,12 @@
 	/* set LAN_OPERATION attributes */
 
 	val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0004, 2,
+	if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0004, 2,
 		&val, 4, &priv->reply_flag) < 0)
 		printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n");
 	else
-		dprintk(KERN_INFO "PacketOrphanLimit set to %d\n",val);
-
-#ifdef 0
-/*
- * I2O spec 2.0: there should be proper default values for other attributes 
- * used in batch mode.
- */
-
-	/* set LAN_RECEIVE_INFO attributes */
-	
-	val = 10; // RxMaxBucketsReply
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 3,
-		&val, 4, &priv->reply_flag) < 0)
-		printk(KERN_WARNING "%s: Unable to set RxMaxBucketsReply.\n",
-			dev->name);
-
-	val = 10; // RxMaxPacketsBuckets
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 4,
-		&val, 4, &priv->reply_flag) < 0)
-		printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n",
-			dev->name);
-
-	/* set LAN_BATCH_CONTROL attributes */
-
-	val = 10; // MaxRxBatchCount
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 5,
-		&val, 4, &priv->reply_flag) < 0)
-		printk(KERN_WARNING "%s: Unable to set MaxRxBatchCount.\n",
-			dev->name);
-
-	val = 10; // MaxTxBatchCount
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 8,
-		&val, 4, &priv->reply_flag) < 0)
-		printk(KERN_WARNING "%s Unable to set MaxTxBatchCount.\n",
-			dev->name);
-#endif
+		dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d\n",
+			dev->name,val);
 
 	return;	
 }
@@ -398,24 +384,26 @@
 	struct i2o_device *i2o_dev = priv->i2o_dev;	
 	struct i2o_controller *iop = i2o_dev->controller;
 
-	i2o_lan_reset(dev);
-	
 	if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 1, 
-		&priv->reply_flag) < 0)
+			    &priv->reply_flag) < 0)
 	{
 		printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
 		return -EAGAIN;
 	}
 	dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", dev->name, i2o_dev->id);
 
+	i2o_lan_reset(dev);
+	
 	dev->tbusy = 0;
 	dev->start = 1;
 
+	priv->packet_tresh = dev->mtu - (dev->mtu >> 3);
+
 	i2o_set_batch_mode(dev);
 	i2o_lan_receive_post(dev);
 
 	MOD_INC_USE_COUNT;
-	
+
 	return 0;
 }
 
@@ -431,15 +419,16 @@
 	dev->tbusy = 1;
 	dev->start = 0;
 
-	if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, 
-	    &priv->reply_flag) < 0)
-	{
-		printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device (tid=%d)\n",
-		       dev->name, i2o_dev->id);
-	}
+// This is the right place for LanSuspend, but it seems to cause 
+// a kernel crash when we are using 82558 HDM proto
 
 	i2o_lan_suspend(dev);
 
+	if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, 
+			    &priv->reply_flag) < 0)
+		printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
+		       "(tid=%d)\n", dev->name, i2o_dev->id);
+
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -452,7 +441,7 @@
  */
 static int i2o_lan_sdu_send(struct sk_buff *skb, struct device *dev)
 {	
-#ifdef 0
+#if 0
 /* not yet tested */
         struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
         struct i2o_device *i2o_dev = priv->i2o_dev;     
@@ -461,13 +450,13 @@
 
 	dprintk(KERN_INFO "LanSDUSend called, skb->len = %d\n", skb->len);
 
-        m = *iop->post_port;
-        if (m == 0xFFFFFFFF)
+        m = I2O_POST_READ32(iop);
+	if (m == 0xFFFFFFFF) 
 	{
-                dev_kfree_skb(skb);     
-                return -1;
-        }
-        msg = bus_to_virt(iop->mem_offset + m);
+		dev_kfree_skb(skb);
+		return -ETIMEDOUT;
+	}    
+	msg = bus_to_virt(iop->mem_offset + m);
 
         msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_4;
         msg[1] = LAN_SDU_SEND<<24 | HOST_TID<<12 | i2o_dev->id; 
@@ -483,7 +472,7 @@
         msg[7] &= 0x0000FFFF;		   // followed by two bytes zeros
         msg[8] = virt_to_bus(skb->data);
         dev->trans_start = jiffies;
-        i2o_post_message(iop,m);
+	i2o_post_message(iop,m);
 
 	dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
 		dev->name,skb->len);
@@ -502,16 +491,15 @@
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
 	struct i2o_device *i2o_dev = priv->i2o_dev;	
 	struct i2o_controller *iop = i2o_dev->controller;
-	u32 m; u32 *msg;
+        u32 m; u32 *msg;
 
-	m = *iop->post_port;
+        m = I2O_POST_READ32(iop);
 	if (m == 0xFFFFFFFF) {
 		dev_kfree_skb(skb);
-		return -1;
-	}
-
+		return -ETIMEDOUT;
+	}    
 	msg = bus_to_virt(iop->mem_offset + m);
-
+	
 	msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4;
 	msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->id;	
 	msg[2] = priv->unit << 16 | lan_context; // IntiatorContext
@@ -524,37 +512,130 @@
 	msg[5] = (u32)skb; 			// TransactionContext
 	msg[6] = virt_to_bus(skb->data);
 
-	i2o_post_message(iop,m);
-
+        i2o_post_message(iop,m);
+        
 	dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
 		dev->name, skb->len);
 
 	return 0;
 }
 
-/*
- * net_device_stats(): Return statistical information.
- */
 static struct net_device_stats *i2o_lan_get_stats(struct device *dev)
 {
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
-	u64 val[16];
+	u64 val64[16];
+	u64 supported_group[4] = { 0, 0, 0, 0 };
 
-	/* query LAN_HISTORICAL_STATS scalar parameter group 0x0100 */
+        if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, 
+        		 val64, sizeof(val64), &priv->reply_flag) < 0)
+        	dprintk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
+	else {
+        	dprintk("%s: LAN_HISTORICAL_STATS queried.\n",dev->name);
+        	priv->stats.tx_packets = val64[0];
+        	priv->stats.tx_bytes   = val64[1];
+        	priv->stats.rx_packets = val64[2];
+        	priv->stats.rx_bytes   = val64[3];
+        	priv->stats.tx_errors  = val64[4];
+        	priv->stats.rx_errors  = val64[5];
+		priv->stats.rx_dropped = val64[6];
+	}
 
-        i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, 
-        		 &val, 16*8, &priv->reply_flag);
-        priv->stats.tx_packets = val[0];
-        priv->stats.tx_bytes   = val[1];
-        priv->stats.rx_packets = val[2];
-        priv->stats.rx_bytes   = val[3];
-        priv->stats.tx_errors  = val[4];
-        priv->stats.rx_errors  = val[5];
-	priv->stats.rx_dropped = val[6];
+        i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0180, -1, 
+        		&supported_group, sizeof(supported_group), &priv->reply_flag);
 
-	// other net_device_stats and FDDI class specific fields follow ...
+	if (supported_group[2]) {
+        	if (i2o_query_scalar(iop, i2o_dev->id, 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 {
+        		dprintk("%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n",dev->name);
+			priv->stats.multicast        = val64[4];
+			priv->stats.rx_length_errors = val64[10];
+			priv->stats.rx_crc_errors    = val64[0];
+		}
+	}
+
+	if (i2o_dev->subclass == I2O_LAN_ETHERNET)
+	{
+		u64 supported_stats = 0;		
+
+        	if (i2o_query_scalar(iop, i2o_dev->id, 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);
+	 		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 (supported_stats != 0) {
+        		if (i2o_query_scalar(iop, i2o_dev->id, 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);
+			else {
+        			dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
+				if (supported_stats & 0x1)
+					priv->stats.rx_over_errors = val64[0];
+				if (supported_stats & 0x4)
+					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, 
+        			 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);
+
+			stats->line_errors		= val64[0];
+			stats->internal_errors		= val64[7];
+			stats->burst_errors		= val64[4];
+			stats->A_C_errors		= val64[2];
+			stats->abort_delimiters		= val64[3];
+			stats->lost_frames		= val64[1];
+			/* stats->recv_congest_count	= ?;  FIXME ??*/
+			stats->frame_copied_errors	= val64[5];
+			stats->frequency_errors		= val64[6];
+			stats->token_errors		= val64[9];
+		}
+		/* Token Ring optional stats not yet defined */
+	}
+#endif
+
+#ifdef CONFIG_FDDI
+	if (i2o_dev->subclass == I2O_LAN_FDDI)
+	{
+        	if (i2o_query_scalar(iop, i2o_dev->id, 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);
+			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);			
+			priv->stats.mac_error_cts = val64[3];
+			priv->stats.mac_lost_cts  = val64[4];
+			priv->stats.mac_rmt_state = val64[5];
+			memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8);
+			memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8);	
+			memcpy(priv->stats.port_lem_cts, &val64[8], 8);
+			memcpy(priv->stats.port_pcm_state, &val64[9], 8);
+		}
+		/* FDDI optional stats not yet defined */
+	}		
+#endif
 
 	return (struct net_device_stats *)&priv->stats;
 }
@@ -569,75 +650,78 @@
 	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
 	u32 filter_mask;
+	u32 work32[64];
 
-	dprintk(KERN_INFO "Entered i2o_lan_set_multicast_list().\n");
+	dprintk(KERN_INFO "%s: Entered i2o_lan_set_multicast_list().\n", dev->name);
 
 return;
 
-/*
- * FIXME: For some reason this kills interrupt handler in i2o_post_wait :-(
- * 
+/* FIXME: Why does the next call kill the interrupt handler?
+ * The same works fine in function lan_open(), and in i2o_proc.c
+ *
+ *  *because its trying to sleep in an irq - this must be async - Alan
  */
-	dprintk(KERN_INFO "dev->flags = 0x%08X, dev->mc_count = 0x%08X\n",
-		dev->flags,dev->mc_count);
 
-	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3, 
-			     &filter_mask, 4, &priv->reply_flag) < 0 )
-		printk(KERN_WARNING "i2o_lan: Unable to query filter mask.\n");	
+	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, -1,
+			     &work32, sizeof(work32), &priv->reply_flag) < 0 ) 
+	{
+		printk(KERN_WARNING "i2o_lan: Unable to query "
+			" LAN_MAC_ADDRESS table.\n");	
+		return;
+	}
+	printk(KERN_INFO "capab mask = 0x%08X, filter mask = 0x%08X\n",
+		work32[7], work32[6]);
 
-	dprintk(KERN_INFO "filter_mask = 0x%08X\n",filter_mask);
+	filter_mask = work32[6];
 
 	if (dev->flags & IFF_PROMISC)
 	{
-        	// Enable promiscuous mode
-
 		filter_mask |= 0x00000002; 
-		if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
-				&filter_mask, 4, &priv->reply_flag) <0)
-			printk(KERN_WARNING "i2o_lan: Unable to enable promiscuous multicast mode.\n");
-		else
-			dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n");
-
-		return;
+		dprintk(KERN_INFO "i2o_lan: Enabling promiscuous mode...\n");
         }
         
-// 	if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS)
-// 	{
-//        	// Disable promiscuous mode, use normal mode.
-// 		hardware_set_filter(NULL);
-//
-//		dprintk(KERN_INFO "i2o_lan: Disabled promiscuous mode, uses normal mode\n"); 
-//
-//		filter_mask = 0x00000000; 
-//		i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
-//				&filter_mask, 4, &priv->reply_flag);
-//		
-//		return;
-//      }
+ 	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > work32[5])
+ 	{
+		filter_mask |= 0x00000000; 
+		dprintk(KERN_INFO "i2o_lan: Enabling all multicast mode...\n");
+	}
 
-        if (dev->mc_count)
-	{
-        	// Walk the address list, and load the filter
-//              hardware_set_filter(dev->mc_list);
+        else if (dev->mc_count)
+	{	
+		struct dev_mc_list *mclist;
+		int i;
+		u8 *work8 = (u8 *)work32;
 
+		dprintk(KERN_INFO "i2o_lan: Enabling multicast mode...\n");
                 filter_mask = 0x00000004; 
-		if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
-				   &filter_mask, 4, &priv->reply_flag) <0)
-			printk(KERN_WARNING "i2o_lan: Unable to enable Promiscuous multicast mode.\n");
-		else
-			dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n");			
-        
-       		return;
-	}
-        
-        // Unicast
-        
-        filter_mask |= 0x00000300; // Broadcast, Multicast disabled
-	if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3,
+
+		/* Fill the multicast addresses */
+		mclist = dev->mc_list;
+
+		for (i = 0; i < dev->mc_count; i++)
+		{	
+			memcpy(work8, mclist->dmi_addr, mclist->dmi_addrlen);
+			work8 += 8;
+			mclist = mclist->next;
+		} 
+
+		if (i2o_clear_table(iop, i2o_dev->id, 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,
+			work32, dev->mc_count*8, &priv->reply_flag) < 0)	
+			dprintk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
+	} 
+	
+	else {
+        	filter_mask |= 0x00000300; // Broadcast, Multicast disabled
+		dprintk(KERN_INFO "i2o_lan: Enabling unicast mode...\n");
+        }
+
+	if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3,
 			&filter_mask, 4, &priv->reply_flag) <0)
-		printk(KERN_WARNING "i2o_lan: Unable to enable unicast mode.\n");
-	else
-		dprintk(KERN_INFO "i2o_lan: Unicast mode enabled.\n");	
+		printk(KERN_WARNING "i2o_lan: Unable to set MAC FilterMask.\n");
 
 	return;
 }
@@ -648,34 +732,31 @@
 	struct i2o_lan_local *priv = NULL;
 	u8 hw_addr[8];
 	unsigned short (*type_trans)(struct sk_buff *, struct device *);
+	void (*unregister_dev)(struct device *dev);
 
 	switch (i2o_dev->subclass)
 	{
 	case I2O_LAN_ETHERNET:
-		/* Note: init_etherdev calls 
-			 ether_setup() and register_netdevice() 
-			 and allocates the priv structure	 */
-
         	dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
 		if (dev == NULL)
 			return NULL;
 		type_trans = eth_type_trans;
+		unregister_dev = unregister_netdev;
 		break;
 
-/*
 #ifdef CONFIG_ANYLAN
 	case I2O_LAN_100VG:
-		printk(KERN_WARNING "i2o_lan: 100base VG not yet supported\n");
+		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));
-		if(dev==NULL)
+		if (dev==NULL)
 			return NULL;
 		type_trans = tr_type_trans;
+		unregister_dev = unregister_trdev;		
 		break;
 #endif
 
@@ -697,23 +778,23 @@
 			return NULL;
 		}
 		type_trans = fddi_type_trans;
-
+		unregister_dev = (void *)unregister_netdevice;
+		
 		fddi_setup(dev);
 		register_netdev(dev);
       	}
 	break;
 #endif
 
-/*
 #ifdef CONFIG_FIBRE_CHANNEL
 	case I2O_LAN_FIBRE_CHANNEL:
-		printk(KERN_WARNING "i2o_lan: Fibre Channel not yet supported\n");
+		printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported\n");
 	break;
 #endif
-*/
+
 	case I2O_LAN_UNKNOWN:
 	default:
-		printk(KERN_WARNING "i2o_lan: LAN type 0x%08X not supported\n",
+		printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported\n",
 		       i2o_dev->subclass);
 		return NULL;
 	}
@@ -721,16 +802,17 @@
 	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)
 	{
-        	printk("%s: Unable to query hardware address.\n",
-		       dev->name);
+        	printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
+		unregister_dev(dev);
+		kfree(dev);
       		return NULL;  
         }
-        
-	dprintk("%s hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+
+	dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
       		dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3],
       		hw_addr[4], hw_addr[5]);
 
@@ -747,8 +829,10 @@
 }
 
 #ifdef MODULE
+#define i2o_lan_init	init_module
+#endif
 
-int init_module(void)
+__init int i2o_lan_init(void)
 {
 	struct device *dev;
 	struct i2o_lan_local *priv;
@@ -772,13 +856,12 @@
 
                 for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next)
 		{
-                        int class = i2o_dev->class;
-
-                        if (class != 0x020) /* not I2O_CLASS_LAN device*/ 
+                        if (i2o_dev->class != I2O_CLASS_LAN) 
                                 continue;
 
 			if (unit == MAX_LAN_CARDS)
 			{
+				i2o_unlock_controller(iop);
 				printk(KERN_WARNING "Too many I2O LAN devices.\n");
 				return -EINVAL;
 			}
@@ -786,7 +869,7 @@
 			dev = i2o_lan_register_device(i2o_dev);
  			if (dev == NULL)
 			{
-				printk(KERN_WARNING "Unable to register I2O LAN device\n");
+				printk(KERN_ERR "Unable to register I2O LAN device\n");
 				continue; // try next one
 			}
 			priv = (struct i2o_lan_local *)dev->priv;	
@@ -800,6 +883,7 @@
 				dev->name, i2o_dev->id, i2o_dev->subclass, 
 				priv->unit);
                 }
+		i2o_unlock_controller(iop);
         }
 
 	dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1);
@@ -807,6 +891,8 @@
 	return 0;
 }
 
+#ifdef MODULE
+
 void cleanup_module(void)
 {
 	int i;
@@ -831,7 +917,7 @@
 #endif
 #ifdef CONFIG_TR
 		case I2O_LAN_TR:
-			unregister_netdev(dev);
+			unregister_trdev(dev);
 			kfree(dev);
 			break;
 #endif
@@ -848,7 +934,11 @@
 }
 
 EXPORT_NO_SYMBOLS;
+
 MODULE_AUTHOR("Univ of Helsinki, CS Department");
 MODULE_DESCRIPTION("I2O Lan OSM");
+
+MODULE_PARM(bucketpost, "i");           // Number of buckets to post
+MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
 
 #endif    
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h
--- v2.3.9/linux/drivers/i2o/i2o_lan.h	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_lan.h	Mon Jul  5 20:09:40 1999
@@ -1,7 +1,7 @@
 /*
  *   	i2o_lan.h		LAN Class specific definitions
  *
- *      I2O LAN CLASS OSM       Prototyping, May 7th 1999
+ *      I2O LAN CLASS OSM       Prototyping, May 17th 1999
  *
  *      (C) Copyright 1999      University of Helsinki,
  *                              Department of Computer Science
@@ -9,16 +9,16 @@
  *      This code is still under development / test.
  *
  *      Author:         Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *    
+ *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>    
  */
 
-#ifndef I2O_LAN_H
-#define I2O_LAN_H
+#ifndef _I2O_LAN_H
+#define _I2O_LAN_H
 
 /* Tunable parameters first */
 
-#define I2O_BUCKET_COUNT 	64
-#define I2O_BUCKET_THRESH	5
+#define I2O_BUCKET_COUNT 	16
+#define I2O_BUCKET_THRESH	0
 
 /* LAN types */
 #define I2O_LAN_ETHERNET	0x0030
@@ -75,7 +75,7 @@
 #define LAN_SDU_SEND		0x3D
 #define LAN_RECEIVE_POST	0x3E
 #define LAN_RESET		0x35
-#define LAN_SUSPEND	0x37
+#define LAN_SUSPEND		0x37
 
 /* LAN DetailedStatusCode defines */
 #define I2O_LAN_DSC_SUCCESS			0x00
@@ -109,4 +109,4 @@
 	struct i2o_packet_info packet_info[1];
 };
  
-#endif /* I2O_LAN_H */
+#endif /* _I2O_LAN_H */
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.9/linux/drivers/i2o/i2o_pci.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/i2o/i2o_pci.c	Mon Jul  5 20:09:40 1999
@@ -10,6 +10,9 @@
  *	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.
+ *
+ *	TODO:
+ *		Support polled I2O PCI controllers. 
  */
  
 #include <linux/module.h>
@@ -187,9 +190,9 @@
 		c=i2o_find_controller(i);
 		if(c==NULL)
 			continue;		
+		i2o_unlock_controller(c);
 		if(c->type == I2O_TYPE_PCI)
 			i2o_delete_controller(c);
-		i2o_unlock_controller(c);
 	}
 }
 
@@ -209,7 +212,6 @@
 			{
 				printk("I2O: Failed to initialize iop%d\n", c->unit);
 				i2o_unlock_controller(c);
-				free_irq(c->bus.pci.irq, c);
 				i2o_delete_controller(c);
 				continue;
 			}
@@ -239,4 +241,13 @@
 	i2o_pci_unload();
 }
 
+#else
+__init void i2o_pci_init(void)
+{
+	if(i2o_pci_scan()>=0)
+	{
+		printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+		i2o_pci_activate();
+	}
+}
 #endif
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.3.9/linux/drivers/i2o/i2o_proc.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/i2o/i2o_proc.c	Mon Jul  5 20:09:40 1999
@@ -17,9 +17,9 @@
  *   DISCLAIMER: This code is still under development/test and may cause
  *   your system to behave unpredictably.  Use at your own discretion.
  *
- *   LAN entries by Juha Sievänen(Juha.Sievanen@cs.Helsinki.FI),
+ *   LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
+ *		    Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
  *   University of Helsinki, Department of Computer Science
- *
  */
 
 /*
@@ -61,8 +61,8 @@
  */
 typedef struct _i2o_proc_entry_t
 {
-	char *name;						/* entry name */
-	mode_t mode;					/* mode */
+	char *name;			/* entry name */
+	mode_t mode;			/* mode */
 	read_proc_t *read_proc;		/* read func */
 	write_proc_t *write_proc;	/* write func */
 } i2o_proc_entry;
@@ -74,66 +74,66 @@
 static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_stat(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_dst(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ds(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_dev(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_ddm(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *);
 static int print_serial_number(char *, int, u8 *, int);
 static int i2o_proc_create_entries(void *, 
-	i2o_proc_entry *p, struct proc_dir_entry *);
-static void i2o_proc_remove_entries(i2o_proc_entry *p, 
-	struct proc_dir_entry *);
+				   i2o_proc_entry *, struct proc_dir_entry *);
+static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *);
 static int i2o_proc_add_controller(struct i2o_controller *, 
-	struct proc_dir_entry * );
+				   struct proc_dir_entry * );
 static void i2o_proc_remove_controller(struct i2o_controller *, 
-	struct proc_dir_entry * );
+				       struct proc_dir_entry * );
 static int create_i2o_procfs(void);
 static int destroy_i2o_procfs(void);
 static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *,
-			struct i2o_message *);
+			   struct i2o_message *);
 
 static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
 				      void *);
 static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *,
 				      void *);
-static int i2o_proc_read_lan_curr_addr(char *, char **, off_t, int, int *,
-				       void *);
-#if 0
 static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *,
 					void *);
-#endif
 static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *,
 					   void *);
 static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *,
 				       void *);
 static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int,
 					     int *, void *);
-#if 0
 static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *,
 				      void *);
-#endif
 static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *,
 				     void *);
 static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *,
 				     void *);
 static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *,
 					void *);
+static int i2o_proc_read_lan_supp_opt_stats(char *, char **, off_t, int, int *,
+					    void *);
 static int i2o_proc_read_lan_opt_tx_hist_stats(char *, char **, off_t, int,
 					       int *, void *);
 static int i2o_proc_read_lan_opt_rx_hist_stats(char *, char **, off_t, int,
 					       int *, void *);
+static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int,
+				       int *, void *);
+static int i2o_proc_read_lan_supp_eth_stats(char *, char **, off_t, int, int *,
+					    void *);
+static int i2o_proc_read_lan_opt_eth_stats(char *, char **, off_t, int, int *,
+					   void *);
+static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *,
+				      void *);
 static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *,
 					void *);
 
-#if 0
-/* Do we really need this??? */
-
-static loff_t i2o_proc_lseek(struct file *file, loff_t off, int whence)
-{
-	return 0;
-}
-#endif
-
 static struct proc_dir_entry *i2o_proc_dir_root;
 
 /*
@@ -156,6 +156,9 @@
 	{"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL},
 	{"stat", S_IFREG|S_IRUGO, i2o_proc_read_stat, NULL},
 	{"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL},
+	{"dst", S_IFREG|S_IRUGO, i2o_proc_read_dst, NULL},
+	{"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL},
+	{"ds", S_IFREG|S_IRUGO, i2o_proc_read_ds, NULL},
 	{NULL, 0, NULL, NULL}
 };
 
@@ -164,8 +167,11 @@
  */
 static i2o_proc_entry generic_dev_entries[] = 
 {
+	{"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL},
+	{"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL},
 	{"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev, NULL},
 	{"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm, NULL},
+	{"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
 	{"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL},
 	{NULL, 0, NULL, NULL}
 };
@@ -200,7 +206,7 @@
 /* private */
 
 /*
- * LAN specific entries
+ * Generic LAN specific entries
  * 
  * Should groups with r/w entries have their own subdirectory?
  *
@@ -210,34 +216,79 @@
 	/* LAN param groups 0000h-0008h */
 	{"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL},
 	{"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL},
-#if 0
 	{"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR,
 	 i2o_proc_read_lan_mcast_addr, NULL},
-#endif
 	{"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR,
 	 i2o_proc_read_lan_batch_control, NULL},
 	{"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL},
 	{"lan_media_operation", S_IFREG|S_IRUGO,
 	 i2o_proc_read_lan_media_operation, NULL},
-#if 0
 	{"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL},
-#endif
 	{"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL},
 	{"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL},
+	/* LAN param groups 0100h, 0180h, 0182h, 0183h */
 	{"lan_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
+	{"lan_supp_opt_stats", S_IFREG|S_IRUGO,
+	 i2o_proc_read_lan_supp_opt_stats, NULL},
 	{"lan_opt_tx_stats", S_IFREG|S_IRUGO,
 	 i2o_proc_read_lan_opt_tx_hist_stats, NULL},
 	{"lan_opt_rx_stats", S_IFREG|S_IRUGO,
 	 i2o_proc_read_lan_opt_rx_hist_stats, NULL},
-	{"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL},
-	/* some useful r/w entries, no write yet */
-	{"lan_curr_addr", S_IFREG|S_IRUGO|S_IWUSR,
-	 i2o_proc_read_lan_curr_addr, NULL},
+	/* TODO: LAN param group 0184h */
+	{NULL, 0, NULL, NULL}
+};
+
+/*
+ * Ethernet specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_eth_entries[] = 
+{
+	/* LAN param groups 0200h, 0280h, 0281h */
+	{"lan_eth_stat", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
+        {"lan_supp_eth_stats", S_IFREG|S_IRUGO,
+	 i2o_proc_read_lan_supp_eth_stats, NULL},
+        {"lan_opt_eth_stats", S_IFREG|S_IRUGO,
+	 i2o_proc_read_lan_opt_eth_stats, NULL},
+	{NULL, 0, NULL, NULL}
+};
+
+/*
+ * Token Ring specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_tr_entries[] = 
+{
+	/* LAN param group 0300h */
+	{"lan_tr_stats", S_IFREG|S_IRUGO,
+	 i2o_proc_read_lan_tr_stats, NULL},
+	/* TODO: LAN param group 0380h, 0381h */
+	{NULL, 0, NULL, NULL}
+};
+
+/*
+ * FDDI specific LAN entries
+ * 
+ */
+static i2o_proc_entry lan_fddi_entries[] = 
+{
+	/* LAN param group 0400h */
+	{"lan_fddi_stats", S_IFREG|S_IRUGO,
+	 i2o_proc_read_lan_fddi_stats, NULL},
+	/* TODO: LAN param group 0480h, 0481h */
 	{NULL, 0, NULL, NULL}
 };
 
+
 static u32 i2o_proc_token = 0;
 
+static char *chtostr(u8 *chars, int n)
+{
+	char tmp[256];
+	tmp[0] = 0;
+        return strncat(tmp, (char *)chars, n);
+}
+
 static char* bus_strings[] = 
 { 
 	"Local Bus", 
@@ -253,13 +304,13 @@
 static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
 
 void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl,
-	struct i2o_message *pmsg)
+		    struct i2o_message *pmsg)
 {
 	i2o_proc_token = I2O_POST_WAIT_OK;
 }
 
 int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, 
-	int *eof, void *data)
+		      int *eof, void *data)
 {
 	struct i2o_controller *c = (struct i2o_controller *)data;
 	pi2o_hrt hrt;
@@ -303,8 +354,10 @@
 
 	if(hrt->hrt_version)
 	{
+		kfree(workspace);
 		len += sprintf(buf+len, 
-					"HRT table for controller is too new a version.\n");
+			       "HRT table for controller is too new a version.\n");
+		spin_unlock(&i2o_proc_lock);
 		return len;
 	}
 
@@ -312,6 +365,7 @@
 
 	if((count * hrt->entry_len + 8) > 2048) {
 		printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
+		kfree(workspace);
 		len += sprintf(buf+len,
 			       "HRT table too big to fit in buffer.\n");
 		spin_unlock(&i2o_proc_lock);
@@ -490,7 +544,8 @@
 						break;
 
 					default:
-						len += sprintf(buf+len, ": Unknown");
+						len += sprintf(buf+len, ": Unknown (0x%02x)",
+							       lct->lct_entry[i].sub_class);
 						break;
 				}
 				break;
@@ -519,7 +574,8 @@
 						break;
 
 					default:
-						len += sprintf(buf+len, ": Unknown Sub-Class");
+						len += sprintf(buf+len, ": Unknown Sub-Class (0x%02x)",
+							       lct->lct_entry[i].sub_class & 0xFF);
 						break;
 				}
 				break;
@@ -642,6 +698,8 @@
 		len += sprintf(buf+len, "Lowest I2O version supported: ");
 		switch(workspace[2]) {
 		case 0x00:
+			len += sprintf(buf+len, "1.0\n");
+			break;
 		case 0x01:
 			len += sprintf(buf+len, "1.5\n");
 			break;
@@ -653,6 +711,8 @@
 		len += sprintf(buf+len, "Highest I2O version supported: ");
 		switch(workspace[3]) {
 		case 0x00:
+			len += sprintf(buf+len, "1.0\n");
+			break;
 		case 0x01:
 			len += sprintf(buf+len, "1.5\n");
 			break;
@@ -666,10 +726,12 @@
 	len += sprintf(buf+len, "Host Unit ID: %0#6x\n", work16[3]);
 	len += sprintf(buf+len, "Segment Number: %0#5x\n", work16[4]&0XFFF);
 
-	len += sprintf(buf+len, "I2O Version: ");
+	len += sprintf(buf+len, "I2O version: ");
 	switch(version)
 	{
 	case 0x00:
+		len += sprintf(buf+len, "1.0\n");
+		break;
 	case 0x01:
 		len += sprintf(buf+len, "1.5\n");
 		break;
@@ -722,7 +784,7 @@
 	switch (workspace[11])
 	{
 	case 0x00:
-		len += sprintf(buf+len, "Memory Mapped\n");
+		len += sprintf(buf+len, "Memory mapped\n");
 		break;
 	case 0x01:
 		len += sprintf(buf+len, "Memory mapped only\n");
@@ -749,26 +811,27 @@
 
 	len += sprintf(buf+len, "LCT Size: %d\n", work32[13]);
 
-	len += sprintf(buf+len, "Desired Private Memory Space: %d kB\n", 
+	len += sprintf(buf+len, "Desired private memory space: %d kB\n", 
 						work32[15]>>10);
-	len += sprintf(buf+len, "Allocated Private Memory Space: %d kB\n", 
+	len += sprintf(buf+len, "Allocated private memory space: %d kB\n", 
 						work32[16]>>10);
-	len += sprintf(buf+len, "Private Memory Base Address: %0#10x\n", 
+	len += sprintf(buf+len, "Private memory base address: %0#10x\n", 
 						work32[17]);
-	len += sprintf(buf+len, "Desired Private I/O Space: %d kB\n", 
+	len += sprintf(buf+len, "Desired private I/O space: %d kB\n", 
 						work32[18]>>10);
-	len += sprintf(buf+len, "Allocated Private I/O Space: %d kB\n", 
+	len += sprintf(buf+len, "Allocated private I/O space: %d kB\n", 
 						work32[19]>>10);
-	len += sprintf(buf+len, "Private I/O Base Address: %0#10x\n", 
+	len += sprintf(buf+len, "Private I/O base address: %0#10x\n", 
 						work32[20]);
 
+	kfree(workspace);
 	spin_unlock(&i2o_proc_lock);
 
 	return len;
 }
 
 int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, 
-	int *eof, void *data)
+		     int *eof, void *data)
 {
 	struct i2o_controller *c = (struct i2o_controller*)data;
 	static u32 work32[5];
@@ -779,14 +842,14 @@
 
 	static char *cpu_table[] =
 	{
-		"Intel 80960 Series",
-		"AMD2900 Series",
-		"Motorola 68000 Series",
-		"ARM Series",
-		"MIPS Series",
-		"Sparc Series",
-		"PowerPC Series",
-		"Intel x86 Series"
+		"Intel 80960 series",
+		"AMD2900 series",
+		"Motorola 68000 series",
+		"ARM series",
+		"MIPS series",
+		"Sparc series",
+		"PowerPC series",
+		"Intel x86 series"
 	};
 
 	spin_lock(&i2o_proc_lock);
@@ -807,15 +870,15 @@
 		return len;
 	}
 
-	len += sprintf(buf, "IOP Hardware Information Table\n");
+	len += sprintf(buf, "IOP Hardware Information Table (group = 0x0000)\n");
 
-	len += sprintf(buf+len, "I2O Vendor ID: %0#6x\n", work16[0]);
-	len += sprintf(buf+len, "Product ID: %0#6x\n", work16[1]);
-	len += sprintf(buf+len, "RAM: %dkB\n", work32[1]>>10);
-	len += sprintf(buf+len, "Non-Volatile Storage: %dkB\n", work32[2]>>10);
+	len += sprintf(buf+len, "I2O Vendor ID        : %0#6x\n", work16[0]);
+	len += sprintf(buf+len, "Product ID           : %0#6x\n", work16[1]);
+	len += sprintf(buf+len, "RAM                  : %dkB\n", work32[1]>>10);
+	len += sprintf(buf+len, "Non-Volatile Storage : %dkB\n", work32[2]>>10);
 
 	hwcap = work32[3];
-	len += sprintf(buf+len, "Capabilities:\n");
+	len += sprintf(buf+len, "Capabilities :\n");
 	if(hwcap&0x00000001)
 		len += sprintf(buf+len, "   Self-booting\n");
 	if(hwcap&0x00000002)
@@ -827,7 +890,7 @@
 	if(hwcap&0x00000010)
 		len += sprintf(buf+len, "   Battery-backed RAM\n");
 
-	len += sprintf(buf+len, "CPU: ");
+	len += sprintf(buf+len, "CPU                 : ");
 	if(work8[16] > 8)
 		len += sprintf(buf+len, "Unknown\n");
 	else
@@ -839,14 +902,407 @@
 	return len;
 }
 
+
+/* Executive group 0003h - Executing DDM List (table) */
+int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, 
+			    int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	int token;
+	int i;
+
+	typedef struct _i2o_exec_execute_ddm_table {
+		u16 ddm_tid;
+		u8  module_type;
+		u8  reserved;
+		u16 i2o_vendor_id;
+		u16 module_id;
+		u8  module_name[24];
+		u8  module_version[4];
+		u32 data_size;
+		u32 code_size;
+	} i2o_exec_execute_ddm_table, *pi2o_exec_execute_ddm_table;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES];
+	} result;
+
+	i2o_exec_execute_ddm_table ddm_table;
+
+	spin_lock(&i2o_proc_lock);
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				c, ADAPTER_TID, proc_context,
+				0x0003, -1,
+				NULL, 0,
+				&result, sizeof(result), &i2o_proc_token);
+
+	if (token<0)
+		switch (token)
+		{
+		case -ETIMEDOUT:
+			len += sprintf(buf, "Timeout reading table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		case -ENOMEM:
+			len += sprintf(buf, "No free memory to read the table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		default:
+			len += sprintf(buf, "Error reading group. BlockStatus %d\n",
+				       token);
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+	len += sprintf(buf+len, "Tid   Type            Vendor Id     Name                     Vrs  Data_size Code_size\n");
+	ddm_table=result.ddm_table[0];
+
+	for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i])
+	{
+		len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
+
+		switch(ddm_table.module_type)
+		{
+		case 0x01:
+			len += sprintf(buf+len, "Downloaded DDM  ");
+			break;			
+		case 0x22:
+			len += sprintf(buf+len, "Embedded DDM    ");
+			break;
+		default:
+			len += sprintf(buf+len, "                ");
+		}
+
+		len += sprintf(buf+len, "%-0#7x", ddm_table.i2o_vendor_id);
+		len += sprintf(buf+len, "%-0#7x", ddm_table.module_id);
+		len += sprintf(buf+len, "%-25s", chtostr(ddm_table.module_name, 24));
+		len += sprintf(buf+len, "%-6s", chtostr(ddm_table.module_version,4));
+		len += sprintf(buf+len, "%8d  ", ddm_table.data_size);
+		len += sprintf(buf+len, "%8d", ddm_table.code_size);
+
+		len += sprintf(buf+len, "\n");
+	}
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Executive group 0004h - Driver Store (scalar) */
+int i2o_proc_read_ds(char *buf, char **start, off_t offset, int len, 
+		     int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	u32 work32[8];
+	int token;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_scalar(c, ADAPTER_TID, proc_context, 0x0004, -1, 
+				 &work32, sizeof(work32), &i2o_proc_token);
+
+	if (token<0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf+len, "Module limit  : %d\n"
+				"Module count  : %d\n"
+				"Current space : %d kB\n"
+				"Free space    : %d kB\n", 
+			work32[0], work32[1], work32[2]>>10, work32[3]>>10);
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Executive group 0005h - Driver Store Table (table) */
+int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len, 
+		      int *eof, void *data)
+{
+	typedef struct _i2o_driver_store {
+		u16 stored_ddm_index;
+		u8  module_type;
+		u8  reserved;
+		u16 i2o_vendor_id;
+		u16 module_id;
+		u8  module_name_version[28];
+		u8  date[8];
+		u32 module_size;
+		u32 mpb_size;
+		u32 module_flags;
+	} i2o_driver_store_table;
+
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	int token;
+	int i;
+
+	struct
+	{
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8  block_status;
+		u8  error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_driver_store_table dst[MAX_I2O_MODULES];
+	} result;
+
+	i2o_driver_store_table dst;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				c, ADAPTER_TID, proc_context,
+				0x0005, -1,
+				NULL, 0,
+				&result, sizeof(result), &i2o_proc_token);
+
+	if (token<0)
+		switch (token)
+		{
+		case -ETIMEDOUT:
+			len += sprintf(buf, "Timeout reading table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		case -ENOMEM:
+			len += sprintf(buf, "No free memory to read the table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		default:
+			len += sprintf(buf, "Error reading group. "
+					"BlockStatus %d\n",token);
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+	len += sprintf(buf+len, "#  Type            Vendor Id      Name                    Vrs  Date     Mod_size Par_size Flags\n");	
+
+	for(i=0, dst=result.dst[0]; i < result.row_count; dst=result.dst[++i])
+	{
+		len += sprintf(buf+len, "%-3d", dst.stored_ddm_index);
+		switch(dst.module_type)
+		{
+		case 0x01:
+			len += sprintf(buf+len, "Downloaded DDM  ");
+			break;			
+		case 0x22:
+			len += sprintf(buf+len, "Embedded DDM    ");
+			break;
+		default:
+			len += sprintf(buf+len, "                ");
+		}
+
+#if 0
+		if(c->i2oversion == 0x02)
+			len += sprintf(buf+len, "%-d", dst.module_state);
+#endif
+
+		len += sprintf(buf+len, "%-0#7x", dst.i2o_vendor_id);
+		len += sprintf(buf+len, "%-0#8x", dst.module_id);
+		len += sprintf(buf+len, "%-29s", chtostr(dst.module_name_version,28));
+		len += sprintf(buf+len, "%-9s", chtostr(dst.date,8));
+		len += sprintf(buf+len, "%8d ", dst.module_size);
+		len += sprintf(buf+len, "%8d ", dst.mpb_size);
+		len += sprintf(buf+len, "0x%04x", dst.module_flags);
+#if 0
+		if(c->i2oversion == 0x02)
+			len += sprintf(buf+len, "%d",
+				       dst.notification_level);
+#endif
+		len += sprintf(buf+len, "\n");
+	}
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Generic group F000h - Params Descriptor (table) */
+int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, 
+			 int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	int token;
+	int i;
+	int rows;
+	u16 work16[2048];
+	u16 *group=work16;
+	int more;
+	
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				c, ADAPTER_TID, proc_context,
+				0xF000, -1,
+				NULL, 0,
+				&work16, sizeof(work16), &i2o_proc_token);
+
+	if (token<0)
+		switch (token)
+		{
+		case -ETIMEDOUT:
+			len += sprintf(buf, "Timeout reading table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		case -ENOMEM:
+			len += sprintf(buf, "No free memory to read the table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		default:
+			len += sprintf(buf, "Error reading table. BlockStatus %d\n",
+				       token);
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+	rows=work16[4];
+	more=work16[5];
+
+	len += sprintf(buf+len, "\nPARAMS DESCRIPTOR TABLE:\n\n");
+	len += sprintf(buf+len, "#  Group   FieldCount RowCount Type   Add Del Clear\n");
+
+	group+=64;
+
+	for(i=0; i < rows; i++,	group+=16)
+	{
+		len += sprintf(buf+len, "%-3d", i);
+
+		len += sprintf(buf+len, "%-0#6x ", group[0]);
+		len += sprintf(buf+len, "%10d ", group[1]);
+		len += sprintf(buf+len, "%8d ", group[2]);
+
+		if(group[3]&0x1)
+			len += sprintf(buf+len, "Table  ");
+		else
+			len += sprintf(buf+len, "Scalar ");
+		if(group[3]&0x2)
+			len += sprintf(buf+len, "x   ");
+		else
+			len += sprintf(buf+len, "    ");
+		if(group[3]&0x4)
+			len += sprintf(buf+len, "x   ");
+		else
+			len += sprintf(buf+len, "    ");
+		if(group[3]&0x8)
+			len += sprintf(buf+len, "x   ");
+		else
+			len += sprintf(buf+len, "    ");
+
+		len += sprintf(buf+len, "\n");
+	}
+
+	if(more)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+/* Generic group F005h - Private message extensions (table) */
+int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, 
+			    int *eof, void *data)
+{
+	struct i2o_controller *c = (struct i2o_controller*)data;
+	int token;
+	int i;
+	int rows;
+	int more;
+	u16 work16[1024];
+	u16 *field=work16;
+
+	spin_lock(&i2o_proc_lock);
+
+	len = 0;
+
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+				c, ADAPTER_TID, proc_context,
+				0xF000, -1,
+				NULL, 0,
+				&work16, sizeof(work16), &i2o_proc_token);
+
+	if (token<0)
+		switch (token)
+		{
+		case -ETIMEDOUT:
+			len += sprintf(buf, "Timeout reading table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		case -ENOMEM:
+			len += sprintf(buf, "No free memory to read the table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		default:
+			len += sprintf(buf, "Error reading field. BlockStatus %d\n",
+				       token);
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
+
+	rows=work16[4];
+	more=work16[5];
+	
+	len += sprintf(buf+len, "Instance#  OrgId  FunctionCode\n");
+
+	field+=64;
+	for(i=0; i < rows; i++,	field+=16)
+	{
+		len += sprintf(buf+len, "%0#9x ", field[0]);
+		len += sprintf(buf+len, "%0#6x ", work16[1]);
+		len += sprintf(buf+len, "%0#6x", work16[2]);
+
+		len += sprintf(buf+len, "\n");
+	}
+
+	if(more)
+		len += sprintf(buf+len, "There is more...\n");
+
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
 int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len, 
-	int *eof, void *data)
+		      int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
 	static u32 work32[128];		// allow for "stuff" + up to 256 byte (max) serial number
 					// == (allow) 512d bytes (max)
 	static u16 *work16 = (u16*)work32;
-	char sz[17];
 	int token;
 
 	spin_lock(&i2o_proc_lock);
@@ -866,34 +1322,21 @@
 		spin_unlock(&i2o_proc_lock);
 		return len;
 	}
+	
+	len += sprintf(buf,     "Device Class  : %s\n", i2o_get_class_name(work16[0]));
+	len += sprintf(buf+len, "Owner TID     : %0#5x\n", work16[2]);
+	len += sprintf(buf+len, "Parent TID    : %0#5x\n", work16[3]);
+	len += sprintf(buf+len, "Vendor info   : %s\n", chtostr((u8 *)(work32+2), 16));
+	len += sprintf(buf+len, "Product info  : %s\n", chtostr((u8 *)(work32+6), 16));
+	len += sprintf(buf+len, "Description   : %s\n", chtostr((u8 *)(work32+10), 16));
+	len += sprintf(buf+len, "Product rev.  : %s\n", chtostr((u8 *)(work32+14), 8));
 
-	len += sprintf(buf, "Device Class: %s\n", i2o_get_class_name(work16[0]));
-
-	len += sprintf(buf+len, "Owner TID:    %0#5x\n", work16[2]);
-	len += sprintf(buf+len, "Parent TID:   %0#5x\n", work16[3]);
-
-	memcpy(sz, work32+2, 16);
-	sz[16] = '\0';
-	len += sprintf(buf+len, "Vendor Info:  %s\n", sz);
-
-	memcpy(sz, work32+6, 16);
-	sz[16] = '\0';
-	len += sprintf(buf+len, "Product Info: %s\n", sz);
-
-	memcpy(sz, work32+10, 16);
-	sz[16] = '\0';
-	len += sprintf(buf+len, "Description:  %s\n", sz);
-
-	memcpy(sz, work32+14, 8);
-	sz[8] = '\0';
-	len += sprintf(buf+len, "Product Revision: %s\n", sz);
-
-	len += sprintf(buf+len, "Serial Number: ");
+	len += sprintf(buf+len, "Serial number : ");
 	len = print_serial_number(buf, len,
 			(u8*)(work32+16),
-							/* allow for SNLen plus
-							 * possible trailing '\0'
-							 */
+						/* allow for SNLen plus
+						 * possible trailing '\0'
+						 */
 			sizeof(work32)-(16*sizeof(u32))-2
 				);
 	len +=  sprintf(buf+len, "\n");
@@ -920,13 +1363,12 @@
 
 
 int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len, 
-	int *eof, void *data)
+		      int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
 	static u32 work32[128];
 	static u16 *work16 = (u16*)work32;
 	int token;
-	char mod[25];
 
 	spin_lock(&i2o_proc_lock);
 	
@@ -946,22 +1388,16 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Registering DDM TID: 0x%03x\n", work16[0]&0xFFF);
-
-	memcpy(mod, (char*)(work16+1), 24);
-	mod[24] = '\0';
-	len += sprintf(buf+len, "Module Name: %s\n", mod);
-
-	memcpy(mod, (char*)(work16+13), 8);
-	mod[8] = '\0';
-	len += sprintf(buf+len, "Module Rev: %s\n", mod);
+	len += sprintf(buf,     "Registering DDM TID : 0x%03x\n", work16[0]&0xFFF);
+	len += sprintf(buf+len, "Module name         : %s\n", chtostr((u8 *)(work16+1), 24));
+	len += sprintf(buf+len, "Module revision     : %s\n", chtostr((u8 *)(work16+13), 8));
 
-	len += sprintf(buf+len, "Serial Number: ");
+	len += sprintf(buf+len, "Serial number       : ");
 	len = print_serial_number(buf, len,
 			(u8*)(work16+17),
-							/* allow for SNLen plus
-							 * possible trailing '\0'
-							 */
+					/* allow for SNLen plus
+					 * possible trailing '\0'
+					 */
 			sizeof(work32)-(17*sizeof(u16))-2
 				);
 	len += sprintf(buf+len, "\n");
@@ -972,13 +1408,12 @@
 }
 
 int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, 
-	int *eof, void *data)
+			int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[128];
+	static u32 work32[256];
 	int token;
-	char sz[65];
-
+ 
 	spin_lock(&i2o_proc_lock);
 	
 	len = 0;
@@ -997,27 +1432,73 @@
 		return len;
 	}
 
-	memcpy(sz, (char*)work32, 64);
-	sz[64] = '\0';
-	len += sprintf(buf, "Device Name: %s\n", sz);
-
-	memcpy(sz, (char*)(work32+16), 64);
-	sz[64] = '\0';
-	len += sprintf(buf+len, "Service Name: %s\n", sz);
-
-	memcpy(sz, (char*)(work32+32), 64);
-	sz[64] = '\0';
-	len += sprintf(buf+len, "Physical Name: %s\n", sz);
-
-	memcpy(sz, (char*)(work32+48), 4);
-	sz[4] = '\0';
-	len += sprintf(buf+len, "Instance Number: %s\n", sz);
+	len += sprintf(buf,     "Device name     : %s\n", chtostr((u8 *)work32, 64));
+	len += sprintf(buf+len, "Service name    : %s\n", chtostr((u8 *)(work32+16), 64));
+	len += sprintf(buf+len, "Physical name   : %s\n", chtostr((u8 *)(work32+32), 64));
+	len += sprintf(buf+len, "Instance number : %s\n", chtostr((u8 *)(work32+48), 4));
+        
+	spin_unlock(&i2o_proc_lock);
+
+	return len;
+}
+
+
+int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, 
+			     int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u32 work32[12];
+	static u16 *work16 = (u16 *)work32;
+	static u8 *work8 = (u8 *)work32;
+	int token;
+
+	spin_lock(&i2o_proc_lock);
+	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->id, proc_context, 
+				 0xF103,	// ParamGroup F103h (SGL Operating Limits)
+				 -1,		// all fields
+				 &work32,
+				 sizeof(work32),
+				 &i2o_proc_token);
+
+	if(token < 0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "SGL chain size        : %d\n", work32[0]);
+	len += sprintf(buf+len, "Max SGL chain size    : %d\n", work32[1]);
+	len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]);
+	len += sprintf(buf+len, "SGL frag count        : %d\n", work16[6]);
+	len += sprintf(buf+len, "Max SGL frag count    : %d\n", work16[7]);
+	len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]);
+
+	if (d->i2oversion == 0x02)
+	{
+		len += sprintf(buf+len, "SGL data alignment    : %d\n", work16[8]);
+		len += sprintf(buf+len, "SGL addr limit        : %d\n", work8[20]);
+		len += sprintf(buf+len, "SGL addr sizes supported : ");
+		if (work8[21] & 0x01)
+			len += sprintf(buf+len, "32 bit ");
+		if (work8[21] & 0x02)
+			len += sprintf(buf+len, "64 bit ");
+		if (work8[21] & 0x04)
+			len += sprintf(buf+len, "96 bit ");
+		if (work8[21] & 0x08)
+			len += sprintf(buf+len, "128 bit ");
+		len += sprintf(buf+len, "\n");
+	}
 
 	spin_unlock(&i2o_proc_lock);
 
 	return len;
 }
 
+
 static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
 {
 	int i;
@@ -1068,22 +1549,22 @@
 
 		case I2O_SNFORMAT_LAN48_MAC:		/* LAN-48 MAC Address */
 			pos += sprintf(buff+pos, 
-						"LAN-48 MAC Address @ %02X:%02X:%02X:%02X:%02X:%02X",
+						"LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X",
 						serialno[2], serialno[3],
 						serialno[4], serialno[5],
 						serialno[6], serialno[7]);
+			break;
 
 		case I2O_SNFORMAT_WAN:			/* WAN MAC Address */
 			/* FIXME: Figure out what a WAN access address looks like?? */
 			pos += sprintf(buff+pos, "WAN Access Address");
 			break;
 
-
 /* plus new in v2.0 */
 		case I2O_SNFORMAT_LAN64_MAC:		/* LAN-64 MAC Address */
 			/* FIXME: Figure out what a LAN-64 address really looks like?? */
 			pos += sprintf(buff+pos, 
-						"LAN-64 MAC Address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
+						"LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
 						serialno[8], serialno[9],
 						serialno[2], serialno[3],
 						serialno[4], serialno[5],
@@ -1114,13 +1595,222 @@
 		case I2O_SNFORMAT_UNKNOWN:		/* Unknown 0    */
 		case I2O_SNFORMAT_UNKNOWN2:		/* Unknown 0xff */
 		default:
-			pos += sprintf(buff+pos, "Unknown Data Format");
+			pos += sprintf(buff+pos, "Unknown data format (0x%02x)",
+				       serialno[0]);
 			break;
 	}
 
 	return pos;
 }
 
+const char * i2o_get_connector_type(int conn)
+{
+	int idx = 16;
+	static char *i2o_connector_type[] = {
+		"OTHER",
+		"UNKNOWN",
+		"AUI",
+		"UTP",
+		"BNC",
+		"RJ45",
+		"STP DB9",
+		"FIBER MIC",
+		"APPLE AUI",
+		"MII",
+		"DB9",
+		"HSSDC",
+		"DUPLEX SC FIBER",
+		"DUPLEX ST FIBER",
+		"TNC/BNC",
+		"HW DEFAULT"
+	};
+
+	switch(conn)
+	{
+	case 0x00000000:
+		idx = 0;
+		break;
+	case 0x00000001:
+		idx = 1;
+		break;
+	case 0x00000002:
+		idx = 2;
+		break;
+	case 0x00000003:
+		idx = 3;
+		break;
+	case 0x00000004:
+		idx = 4;
+		break;
+	case 0x00000005:
+		idx = 5;
+		break;
+	case 0x00000006:
+		idx = 6;
+		break;
+	case 0x00000007:
+		idx = 7;
+		break;
+	case 0x00000008:
+		idx = 8;
+		break;
+	case 0x00000009:
+		idx = 9;
+		break;
+	case 0x0000000A:
+		idx = 10;
+		break;
+	case 0x0000000B:
+		idx = 11;
+		break;
+	case 0x0000000C:
+		idx = 12;
+		break;
+	case 0x0000000D:
+		idx = 13;
+		break;
+	case 0x0000000E:
+		idx = 14;
+		break;
+	case 0xFFFFFFFF:
+		idx = 15;
+		break;
+	}
+
+	return i2o_connector_type[idx];
+}
+
+
+const char * i2o_get_connection_type(int conn)
+{
+	int idx = 0;
+	static char *i2o_connection_type[] = {
+		"Unknown",
+		"AUI",
+		"10BASE5",
+		"FIORL",
+		"10BASE2",
+		"10BROAD36",
+		"10BASE-T",
+		"10BASE-FP",
+		"10BASE-FB",
+		"10BASE-FL",
+		"100BASE-TX",
+		"100BASE-FX",
+		"100BASE-T4",
+		"1000BASE-SX",
+		"1000BASE-LX",
+		"1000BASE-CX",
+		"1000BASE-T",
+		"100VG-ETHERNET",
+		"100VG-TOKEN RING",
+		"4MBIT TOKEN RING",
+		"16 Mb Token Ring",
+		"125 MBAUD FDDI",
+		"Point-to-point",
+		"Arbitrated loop",
+		"Public loop",
+		"Fabric",
+		"Emulation",
+		"Other",
+		"HW default"
+	};
+
+	switch(conn)
+	{
+	case I2O_LAN_UNKNOWN:
+		idx = 0;
+		break;
+	case I2O_LAN_AUI:
+		idx = 1;
+		break;
+	case I2O_LAN_10BASE5:
+		idx = 2;
+		break;
+	case I2O_LAN_FIORL:
+		idx = 3;
+		break;
+	case I2O_LAN_10BASE2:
+		idx = 4;
+		break;
+	case I2O_LAN_10BROAD36:
+		idx = 5;
+		break;
+	case I2O_LAN_10BASE_T:
+		idx = 6;
+		break;
+	case I2O_LAN_10BASE_FP:
+		idx = 7;
+		break;
+	case I2O_LAN_10BASE_FB:
+		idx = 8;
+		break;
+	case I2O_LAN_10BASE_FL:
+		idx = 9;
+		break;
+	case I2O_LAN_100BASE_TX:
+		idx = 10;
+		break;
+	case I2O_LAN_100BASE_FX:
+		idx = 11;
+		break;
+	case I2O_LAN_100BASE_T4:
+		idx = 12;
+		break;
+	case I2O_LAN_1000BASE_SX:
+		idx = 13;
+		break;
+	case I2O_LAN_1000BASE_LX:
+		idx = 14;
+		break;
+	case I2O_LAN_1000BASE_CX:
+		idx = 15;
+		break;
+	case I2O_LAN_1000BASE_T:
+		idx = 16;
+		break;
+	case I2O_LAN_100VG_ETHERNET:
+		idx = 17;
+		break;
+	case I2O_LAN_100VG_TR:
+		idx = 18;
+		break;
+	case I2O_LAN_4MBIT:
+		idx = 19;
+		break;
+	case I2O_LAN_16MBIT:
+		idx = 20;
+		break;
+	case I2O_LAN_125MBAUD:
+		idx = 21;
+		break;
+	case I2O_LAN_POINT_POINT:
+		idx = 22;
+		break;
+	case I2O_LAN_ARB_LOOP:
+		idx = 23;
+		break;
+	case I2O_LAN_PUBLIC_LOOP:
+		idx = 24;
+		break;
+	case I2O_LAN_FABRIC:
+		idx = 25;
+		break;
+	case I2O_LAN_EMULATION:
+		idx = 26;
+		break;
+	case I2O_LAN_OTHER:
+		idx = 27;
+		break;
+	case I2O_LAN_DEFAULT:
+		idx = 28;
+		break;
+	}
+
+	return i2o_connection_type[idx];
+}
+
+
 /* LAN group 0000h - Device info (scalar) */
 int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, 
 			       int *eof, void *data)
@@ -1145,7 +1835,7 @@
 		return len;
 	}
 
-	len += sprintf(buf, "LAN Type ........... ");
+	len += sprintf(buf, "LAN Type            : ");
 	switch (work16[0])
 	{
 	case 0x0030:
@@ -1164,7 +1854,7 @@
 		len += sprintf(buf+len, "Fibre Channel, ");
 		break;
 	default:
-		len += sprintf(buf+len, "Unknown type, ");
+		len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]);
 		break;
 	}
 
@@ -1178,7 +1868,7 @@
 	else
 		len += sprintf(buf+len, "simplex\n");
 
-	len += sprintf(buf+len, "Address format:      ");
+	len += sprintf(buf+len, "Address format      : ");
 	switch(work8[4]) {
 	case 0x00:
 		len += sprintf(buf+len, "IEEE 48bit\n");
@@ -1187,11 +1877,11 @@
 		len += sprintf(buf+len, "FC IEEE\n");
 		break;
 	default:
-		len += sprintf(buf+len, "Unknown\n");
+		len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]);
 		break;
 	}
 
-	len += sprintf(buf+len, "State:               ");
+	len += sprintf(buf+len, "State               : ");
 	switch(work8[5])
 	{
 	case 0x00:
@@ -1210,7 +1900,14 @@
 		len += sprintf(buf+len, "Resetting\n");
 		break;
 	case 0x05:
-		len += sprintf(buf+len, "Error\n");
+		len += sprintf(buf+len, "ERROR: ");
+		if(work16[3]&0x0001)
+			len += sprintf(buf+len, "TxCU inoperative ");
+		if(work16[3]&0x0002)
+			len += sprintf(buf+len, "RxCU inoperative ");
+		if(work16[3]&0x0004)
+			len += sprintf(buf+len, "Local mem alloc ");
+		len += sprintf(buf+len, "\n");
 		break;
 	case 0x06:
 		len += sprintf(buf+len, "Operational no Rx\n");
@@ -1223,27 +1920,18 @@
 		break;
 	}
 
-	len += sprintf(buf+len, "Error status:      ");
-	if(work16[3]&0x0001)
-		len += sprintf(buf+len, "Transmit Control Unit Inoperative ");
-	if(work16[3]&0x0002)
-		len += sprintf(buf+len, "Receive Control Unit Inoperative\n");
-	if(work16[3]&0x0004)
-		len += sprintf(buf+len, "Local memory Allocation Error\n");
-	len += sprintf(buf+len, "\n");
-
-	len += sprintf(buf+len, "Min Packet size:     %d\n", work32[2]);
-	len += sprintf(buf+len, "Max Packet size:     %d\n", work32[3]);
-	len += sprintf(buf+len, "HW Address:          "
+	len += sprintf(buf+len, "Min packet size     : %d\n", work32[2]);
+	len += sprintf(buf+len, "Max packet size     : %d\n", work32[3]);
+	len += sprintf(buf+len, "HW address          : "
 		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
 		       work8[16],work8[17],work8[18],work8[19],
 		       work8[20],work8[21],work8[22],work8[23]);
 
-	len += sprintf(buf+len, "Max Tx Wire Speed:   " FMT_U64_HEX " bps\n", U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "Max Rx Wire Speed:   " FMT_U64_HEX " bps\n", U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "Max Tx wire speed   : %d bps\n", work64[3]);
+	len += sprintf(buf+len, "Max Rx wire speed   : %d bps\n", work64[4]);
 
-	len += sprintf(buf+len, "Min SDU packet size: 0x%08x\n", work32[10]);
-	len += sprintf(buf+len, "Max SDU packet size: 0x%08x\n", work32[11]);
+	len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]);
+	len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]);
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -1270,60 +1958,65 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Active address: "
+	len += sprintf(buf,     "Active address          : "
 		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
 		       work8[0],work8[1],work8[2],work8[3],
 		       work8[4],work8[5],work8[6],work8[7]);
-	len += sprintf(buf+len, "Current address: "
+	len += sprintf(buf+len, "Current address         : "
 		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
 		       work8[8],work8[9],work8[10],work8[11],
 		       work8[12],work8[13],work8[14],work8[15]);
-	len += sprintf(buf+len, "Functional address mask: "
+	len += sprintf(buf+len, "Functional address mask : "
 		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
 		       work8[16],work8[17],work8[18],work8[19],
 		       work8[20],work8[21],work8[22],work8[23]);
 
-	len += sprintf(buf+len, "Filter mask: 0x%08x\n", work32[6]);
-	len += sprintf(buf+len, "HW/DDM capabilities: 0x%08x\n", work32[7]);
-	len += sprintf(buf+len, "    Unicast packets %ssupported (%sabled)\n",
-		       (work32[7]&0x00000001)?"":"not ",
-		       (work32[6]&0x00000001)?"en":"dis");
-	len += sprintf(buf+len, "    Promiscuous mode %ssupported (%sabled)\n",
-		       (work32[7]&0x00000002)?"":"not",
-		       (work32[6]&0x00000002)?"en":"dis");
-	len += sprintf(buf+len,
-		       "    Multicast promiscuous mode %ssupported (%sabled)\n",
-		       (work32[7]&0x00000004)?"":"not ",
-		       (work32[6]&0x00000004)?"en":"dis");
-	len += sprintf(buf+len,
-		       "    Broadcast Reception disabling %ssupported (%sabled)\n",
-		       (work32[7]&0x00000100)?"":"not ",
-		       (work32[6]&0x00000100)?"en":"dis");
-	len += sprintf(buf+len,
-		       "    Multicast Reception disabling %ssupported (%sabled)\n",
-		       (work32[7]&0x00000200)?"":"not ",
-		       (work32[6]&0x00000200)?"en":"dis");
-	len += sprintf(buf+len,
-		       "    Functional address disabling %ssupported (%sabled)\n",
-		       (work32[7]&0x00000400)?"":"not ",
-		       (work32[6]&0x00000400)?"en":"dis");
+	len += sprintf(buf+len, "HW/DDM capabilities : 0x%08x\n", work32[7]);
+	len += sprintf(buf+len, "    Unicast packets %ssupported\n",
+		       (work32[7]&0x00000001)?"":"not ");
+	len += sprintf(buf+len, "    Promiscuous mode %ssupported\n",
+		       (work32[7]&0x00000002)?"":"not");
+	len += sprintf(buf+len, "    Promiscuous multicast mode %ssupported\n",
+		       (work32[7]&0x00000004)?"":"not ");
+	len += sprintf(buf+len,"    Broadcast reception disabling %ssupported\n",
+		       (work32[7]&0x00000100)?"":"not ");
+	len += sprintf(buf+len,"    Multicast reception disabling %ssupported\n",
+		       (work32[7]&0x00000200)?"":"not ");
+	len += sprintf(buf+len,"    Functional address disabling %ssupported\n",
+		       (work32[7]&0x00000400)?"":"not ");
 	len += sprintf(buf+len, "    MAC reporting %ssupported\n",
-		       (work32[7]&0x00000800)?"":"not ");		       
-
-	len += sprintf(buf+len, "    MAC Reporting mode: ");
-	if (work32[6]&0x00000800)
-		len += sprintf(buf+len, "Pass only priority MAC packets\n");
-	else if (work32[6]&0x00001000)
-		len += sprintf(buf+len, "Pass all MAC packets\n");
-	else if (work32[6]&0x00001800)
-		len += sprintf(buf+len, "Pass all MAC packets (promiscuous)\n");
-	else
-		len += sprintf(buf+len, "Do not pass MAC packets\n");
+		       (work32[7]&0x00000800)?"":"not ");
 
-	len += sprintf(buf+len, "Number of multicast addesses: %d\n", work32[8]);
-	len += sprintf(buf+len, "Perfect filtering for max %d multicast addesses\n",
+	len += sprintf(buf+len, "Filter mask : 0x%08x\n", work32[6]);
+	len += sprintf(buf+len, "    Unicast packets %s\n",
+		(work32[6]&0x00000001)?"rejected":"enabled");
+	len += sprintf(buf+len, "    Promiscuous mode %s\n",
+		(work32[6]&0x00000002)?"enabled":"disabled");
+	len += sprintf(buf+len, "    Promiscuous multicast mode %s\n",
+		(work32[6]&0x00000004)?"enabled":"disabled");	
+	len += sprintf(buf+len, "    Broadcast packets %s\n",
+		(work32[6]&0x00000100)?"rejected":"enabled");
+	len += sprintf(buf+len, "    Multicast packets %s\n",
+		(work32[6]&0x00000200)?"rejected":"enabled");
+	len += sprintf(buf+len, "    Functional address %s\n",
+		       (work32[6]&0x00000400)?"ignored":"enabled");
+		       
+	if (work32[7]&0x00000800)
+	{		       
+		len += sprintf(buf+len, "    MAC reporting mode : ");
+		if (work32[6]&0x00000800)
+			len += sprintf(buf+len, "Pass only priority MAC packets to user\n");
+		else if (work32[6]&0x00001000)
+			len += sprintf(buf+len, "Pass all MAC packets to user\n");
+		else if (work32[6]&0x00001800)
+			len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n");
+		else
+			len += sprintf(buf+len, "Do not pass MAC packets to user\n");
+	}
+	len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]);
+	len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n",
 		       work32[9]);
-	len += sprintf(buf+len, "Imperfect filtering for max %d multicast addesses\n",
+	len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n",
 		       work32[10]);
 
 	spin_unlock(&i2o_proc_lock);
@@ -1331,97 +2024,76 @@
 	return len;
 }
 
-/* LAN group 0001h, field 1 - Current MAC (scalar) */
-int i2o_proc_read_lan_curr_addr(char *buf, char **start, off_t offset, int len,
-				int *eof, void *data)
-{
-	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[2];
-	static u8 *work8 = (u8*)work32;
-	int token;
-
-	spin_lock(&i2o_proc_lock);	
-	len = 0;
-
-	token = i2o_query_scalar(d->controller, d->id, proc_context, 
-				 0x0001, 2, &work32, 8, &i2o_proc_token);
-	if(token < 0)
-	{
-		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-
-	len += sprintf(buf, "Current address: "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		       work8[0],work8[1],work8[2],work8[3],
-		       work8[4],work8[5],work8[6],work8[7]);
-
-	spin_unlock(&i2o_proc_lock);
-	return len;
-}
-
-
-#if 0
 /* LAN group 0002h - Multicast MAC address table (table) */
-int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, int len, 
-				 int *eof, void *data)
+int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
-	static u8 work8[32];
-	static u32 field32[8];
+	static u32 field32[64];
 	static u8 *field8 = (u8 *)field32;
+	static u16 *field16 = (u16 *)field32;
 	int token;
+	int i;
 
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_table_polled(d->controller, d->id, &work8, 32,
-				       0x0002, 0, field32, 8);
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+			d->controller, d->id, proc_context, 0x0002, -1, 
+			NULL, 0, &field32, sizeof(field32),
+			&i2o_proc_token);
+
+	if (token<0)
+		switch (token) {
+		case -ETIMEDOUT:
+			len += sprintf(buf, "Timeout reading table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		case -ENOMEM:
+			len += sprintf(buf, "No free memory to read the table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		default:
+			len += sprintf(buf, "Error reading field. BlockStatus %d\n",
+				       token);
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
 
-	switch (token) {
-	case -ETIMEDOUT:
-		len += sprintf(buf, "Timeout reading table.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-		break;
-	case -ENOMEM:
-		len += sprintf(buf, "No free memory to read the table.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-		break;
-	case -EBADR:
-		len += sprintf(buf, "Error reading field.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-		break;
-	default:
-		break;
-	}
+	len += sprintf(buf, "RowCount=%d, MoreFlag=%d\n", 
+		       field16[0], field16[1]);
 
-	len += sprintf(buf, "Multicast MAC address: "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		       field8[0],field8[1],field8[2],field8[3],
-		       field8[4],field8[5],field8[6],field8[7]);
+	field8=(u8 *)&field16[2];
+
+	for(i=0; i<field16[0]; i++, field8+=8)
+	{
+		len += sprintf(buf+len, "MC MAC address[%d]: "
+			       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+			       i,
+			       field8[0], field8[1], field8[2],
+			       field8[3], field8[4], field8[5],
+			       field8[6], field8[7]);
+	}
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
 }
-#endif
 
 /* LAN group 0003h - Batch Control (scalar) */
 int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
 				    int len, int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[18];
+	static u32 work32[9];
 	int token;
 
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
 	token = i2o_query_scalar(d->controller, d->id, proc_context, 
-				 0x0003, -1, &work32, 72, &i2o_proc_token);
+				 0x0003, -1, &work32, 9*4, &i2o_proc_token);
 	if(token < 0)
 	{
 		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
@@ -1443,26 +2115,26 @@
 	len += sprintf(buf+len, "\n");
 
 	if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
-		len += sprintf(buf+len, "Rising Load Delay: %d ms\n",
+		len += sprintf(buf+len, "Rising load delay      : %d ms\n",
 			       work32[1]/10);
-		len += sprintf(buf+len, "Rising Load Threshold: %d ms\n",
+		len += sprintf(buf+len, "Rising load threshold  : %d ms\n",
 			       work32[2]/10);
-		len += sprintf(buf+len, "Falling Load Delay: %d ms\n",
+		len += sprintf(buf+len, "Falling load delay     : %d ms\n",
 			       work32[3]/10);
-		len += sprintf(buf+len, "Falling Load Threshold: %d ms\n",
+		len += sprintf(buf+len, "Falling load threshold : %d ms\n",
 			       work32[4]/10);
 	}
 
-	len += sprintf(buf+len, "Max Rx Batch Count: %d\n", work32[5]);
-	len += sprintf(buf+len, "Max Rx Batch Delay: %d\n", work32[6]);
+	len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
+	len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
 
 	if(d->i2oversion == 0x00) {
 		len += sprintf(buf+len,
-			       "Transmission Completion Reporting Delay: %d ms\n",
+			       "Transmission completion reporting delay : %d ms\n",
 			       work32[7]);
 	} else {
-		len += sprintf(buf+len, "Max Tx Batch Delay: %d\n", work32[7]);
-		len += sprintf(buf+len, "Max Tx Batch Count: %d\n", work32[8]);
+		len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
+		len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
 	}
 
 	spin_unlock(&i2o_proc_lock);
@@ -1489,14 +2161,14 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Packet prepadding (32b words): %d\n", work32[0]);
-	len += sprintf(buf+len, "Transmission error reporting: %s\n",
+	len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]);
+	len += sprintf(buf+len, "Transmission error reporting  : %s\n",
 		       (work32[1]&1)?"on":"off");
-	len += sprintf(buf+len, "Bad packet handling: %s\n",
+	len += sprintf(buf+len, "Bad packet handling           : %s\n",
 		       (work32[1]&0x2)?"by host":"by DDM");		      
-	len += sprintf(buf+len, "Packet orphan limit: %d\n", work32[2]);
+	len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
 
-	len += sprintf(buf+len, "Tx modes:\n");
+	len += sprintf(buf+len, "Tx modes :\n");
 	if (work32[3]&0x00000004)
 		len += sprintf(buf+len, "    HW CRC supressed\n");
 	else
@@ -1514,7 +2186,7 @@
 	if (work32[3]&0x00002000)
 		len += sprintf(buf+len, "    Loopback packet not delivered\n");
 
-	len += sprintf(buf+len, "Rx modes:\n");
+	len += sprintf(buf+len, "Rx modes :\n");
 	if (work32[4]&0x00000004)
 		len += sprintf(buf+len, "    FCS in payload\n");
 	if (work32[4]&0x00000100)
@@ -1554,402 +2226,127 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Connector type: ");
-	switch(work32[0])
-	{
-	case 0x00000000:
-		len += sprintf(buf+len, "OTHER\n");
-		break;
-	case 0x00000001:
-		len += sprintf(buf+len, "UNKNOWN\n");
-		break;
-	case 0x00000002:
-		len += sprintf(buf+len, "AUI\n");
-		break;
-	case 0x00000003:
-		len += sprintf(buf+len, "UTP\n");
-		break;
-	case 0x00000004:
-		len += sprintf(buf+len, "BNC\n");
-		break;
-	case 0x00000005:
-		len += sprintf(buf+len, "RJ45\n");
-		break;
-	case 0x00000006:
-		len += sprintf(buf+len, "STP DB9\n");
-		break;
-	case 0x00000007:
-		len += sprintf(buf+len, "FIBER MIC\n");
-		break;
-	case 0x00000008:
-		len += sprintf(buf+len, "APPLE AUI\n");
-		break;
-	case 0x00000009:
-		len += sprintf(buf+len, "MII\n");
-		break;
-	case 0x0000000A:
-		len += sprintf(buf+len, "DB9\n");
-		break;
-	case 0x0000000B:
-		len += sprintf(buf+len, "HSSDC\n");
-		break;
-	case 0x0000000C:
-		len += sprintf(buf+len, "DUPLEX SC FIBER\n");
-		break;
-	case 0x0000000D:
-		len += sprintf(buf+len, "DUPLEX ST FIBER\n");
-		break;
-	case 0x0000000E:
-		len += sprintf(buf+len, "TNC/BNC\n");
-		break;
-	case 0xFFFFFFFF:
-		len += sprintf(buf+len, "HW DEFAULT\n");
-		break;
-	}
-
-	len += sprintf(buf+len, "Connection type: ");
-	switch(work32[1])
-	{
-	case I2O_LAN_UNKNOWN:
-		len += sprintf(buf+len, "UNKNOWN\n");
-		break;
-	case I2O_LAN_AUI:
-		len += sprintf(buf+len, "AUI\n");
-		break;
-	case I2O_LAN_10BASE5:
-		len += sprintf(buf+len, "10BASE5\n");
-		break;
-	case I2O_LAN_FIORL:
-		len += sprintf(buf+len, "FIORL\n");
-		break;
-	case I2O_LAN_10BASE2:
-		len += sprintf(buf+len, "10BASE2\n");
-		break;
-	case I2O_LAN_10BROAD36:
-		len += sprintf(buf+len, "10BROAD36\n");
-		break;
-	case I2O_LAN_10BASE_T:
-		len += sprintf(buf+len, "10BASE-T\n");
-		break;
-	case I2O_LAN_10BASE_FP:
-		len += sprintf(buf+len, "10BASE-FP\n");
-		break;
-	case I2O_LAN_10BASE_FB:
-		len += sprintf(buf+len, "10BASE-FB\n");
-		break;
-	case I2O_LAN_10BASE_FL:
-		len += sprintf(buf+len, "10BASE-FL\n");
-		break;
-	case I2O_LAN_100BASE_TX:
-		len += sprintf(buf+len, "100BASE-TX\n");
-		break;
-	case I2O_LAN_100BASE_FX:
-		len += sprintf(buf+len, "100BASE-FX\n");
-		break;
-	case I2O_LAN_100BASE_T4:
-		len += sprintf(buf+len, "100BASE-T4\n");
-		break;
-	case I2O_LAN_1000BASE_SX:
-		len += sprintf(buf+len, "1000BASE-SX\n");
-		break;
-	case I2O_LAN_1000BASE_LX:
-		len += sprintf(buf+len, "1000BASE-LX\n");
-		break;
-	case I2O_LAN_1000BASE_CX:
-		len += sprintf(buf+len, "1000BASE-CX\n");
-		break;
-	case I2O_LAN_1000BASE_T:
-		len += sprintf(buf+len, "1000BASE-T\n");
-		break;
-	case I2O_LAN_100VG_ETHERNET:
-		len += sprintf(buf+len, "100VG-ETHERNET\n");
-		break;
-	case I2O_LAN_100VG_TR:
-		len += sprintf(buf+len, "100VG-TOKEN RING\n");
-		break;
-	case I2O_LAN_4MBIT:
-		len += sprintf(buf+len, "4MBIT TOKEN RING\n");
-		break;
-	case I2O_LAN_16MBIT:
-		len += sprintf(buf+len, "16 Mb Token Ring\n");
-		break;
-	case I2O_LAN_125MBAUD:
-		len += sprintf(buf+len, "125 MBAUD FDDI\n");
-		break;
-	case I2O_LAN_POINT_POINT:
-		len += sprintf(buf+len, "Point-to-point\n");
-		break;
-	case I2O_LAN_ARB_LOOP:
-		len += sprintf(buf+len, "Arbitrated loop\n");
-		break;
-	case I2O_LAN_PUBLIC_LOOP:
-		len += sprintf(buf+len, "Public loop\n");
-		break;
-	case I2O_LAN_FABRIC:
-		len += sprintf(buf+len, "Fabric\n");
-		break;
-	case I2O_LAN_EMULATION:
-		len += sprintf(buf+len, "Emulation\n");
-		break;
-	case I2O_LAN_OTHER:
-		len += sprintf(buf+len, "Other\n");
-		break;
-	case I2O_LAN_DEFAULT:
-		len += sprintf(buf+len, "HW default\n");
-		break;
-	}
-
-	len += sprintf(buf+len, "Current Tx Wire Speed: " FMT_U64_HEX " bps\n",
-		       U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "Current Rx Wire Speed: " FMT_U64_HEX " bps\n",
-		       U64_VAL(&work64[2]));
-
-	len += sprintf(buf+len, "%s duplex\n", (work8[24]&1)?"Full":"Half");
-
-	len += sprintf(buf+len, "Link status: ");
-	if(work8[25] == 0x00)
-		len += sprintf(buf+len, "Unknown\n");
-	else if(work8[25] == 0x01)
-		len += sprintf(buf+len, "Normal\n");
-	else if(work8[25] == 0x02)
-		len += sprintf(buf+len, "Failure\n");
-	else if(work8[25] == 0x03)
-		len += sprintf(buf+len, "Reset\n");
-	else
-		len += sprintf(buf+len, "Unspecified\n");
+	len += sprintf(buf, "Connector type         : %s\n",
+		       i2o_get_connector_type(work32[0]));
+	len += sprintf(buf+len, "Connection type        : %s\n",
+		       i2o_get_connection_type(work32[1]));
+
+	len += sprintf(buf+len, "Current Tx wire speed  : %d bps\n", work64[1]);
+	len += sprintf(buf+len, "Current Rx wire speed  : %d bps\n", work64[2]);
+
+	len += sprintf(buf+len, "Duplex mode            : %s duplex\n", 
+			(work8[24]&1)?"Full":"Half");
+	len += sprintf(buf+len, "Link status            : ");
+	if(work8[25] == 0x00)
+		len += sprintf(buf+len, "Unknown\n");
+	else if(work8[25] == 0x01)
+		len += sprintf(buf+len, "Normal\n");
+	else if(work8[25] == 0x02)
+		len += sprintf(buf+len, "Failure\n");
+	else if(work8[25] == 0x03)
+		len += sprintf(buf+len, "Reset\n");
+	else
+		len += sprintf(buf+len, "Unspecified\n");
 
 	if (d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
-		len += sprintf(buf+len, "Bad packets handled by: %s\n",
+		len += sprintf(buf+len, "Bad packets handled by : %s\n",
 			       (work8[26] == 0xFF)?"host":"DDM");
 	}
 	if (d->i2oversion != 0x00) {
-		len += sprintf(buf+len, "Duplex mode target: ");
+		len += sprintf(buf+len, "Duplex mode target     : ");
 		switch (work8[27]) {
 		case 0:
-			len += sprintf(buf+len, "Half Duplex\n");
+			len += sprintf(buf+len, "Half duplex\n");
 			break;
 		case 1:
-			len += sprintf(buf+len, "Full Duplex\n");
-			break;
-		default:
-			len += sprintf(buf+len, "\n");
-			break;
-		}
-
-		len += sprintf(buf+len, "Connector type target: ");
-		switch(work32[7])
-		{
-		case 0x00000000:
-			len += sprintf(buf+len, "OTHER\n");
-			break;
-		case 0x00000001:
-			len += sprintf(buf+len, "UNKNOWN\n");
-			break;
-		case 0x00000002:
-			len += sprintf(buf+len, "AUI\n");
-			break;
-		case 0x00000003:
-			len += sprintf(buf+len, "UTP\n");
-			break;
-		case 0x00000004:
-			len += sprintf(buf+len, "BNC\n");
-			break;
-		case 0x00000005:
-			len += sprintf(buf+len, "RJ45\n");
-			break;
-		case 0x00000006:
-			len += sprintf(buf+len, "STP DB9\n");
-			break;
-		case 0x00000007:
-			len += sprintf(buf+len, "FIBER MIC\n");
-			break;
-		case 0x00000008:
-			len += sprintf(buf+len, "APPLE AUI\n");
-			break;
-		case 0x00000009:
-			len += sprintf(buf+len, "MII\n");
-			break;
-		case 0x0000000A:
-			len += sprintf(buf+len, "DB9\n");
-			break;
-		case 0x0000000B:
-			len += sprintf(buf+len, "HSSDC\n");
-			break;
-		case 0x0000000C:
-			len += sprintf(buf+len, "DUPLEX SC FIBER\n");
-			break;
-		case 0x0000000D:
-			len += sprintf(buf+len, "DUPLEX ST FIBER\n");
-			break;
-		case 0x0000000E:
-			len += sprintf(buf+len, "TNC/BNC\n");
-			break;
-		case 0xFFFFFFFF:
-			len += sprintf(buf+len, "HW DEFAULT\n");
+			len += sprintf(buf+len, "Full duplex\n");
 			break;
 		default:
 			len += sprintf(buf+len, "\n");
 			break;
 		}
 
-		len += sprintf(buf+len, "Connection type target: ");
-		switch(work32[8])
-		{
-		case I2O_LAN_UNKNOWN:
-			len += sprintf(buf+len, "UNKNOWN\n");
-			break;
-		case I2O_LAN_AUI:
-			len += sprintf(buf+len, "AUI\n");
-			break;
-		case I2O_LAN_10BASE5:
-			len += sprintf(buf+len, "10BASE5\n");
-			break;
-		case I2O_LAN_FIORL:
-			len += sprintf(buf+len, "FIORL\n");
-			break;
-		case I2O_LAN_10BASE2:
-			len += sprintf(buf+len, "10BASE2\n");
-			break;
-		case I2O_LAN_10BROAD36:
-			len += sprintf(buf+len, "10BROAD36\n");
-			break;
-		case I2O_LAN_10BASE_T:
-			len += sprintf(buf+len, "10BASE-T\n");
-			break;
-		case I2O_LAN_10BASE_FP:
-			len += sprintf(buf+len, "10BASE-FP\n");
-			break;
-		case I2O_LAN_10BASE_FB:
-			len += sprintf(buf+len, "10BASE-FB\n");
-			break;
-		case I2O_LAN_10BASE_FL:
-			len += sprintf(buf+len, "10BASE-FL\n");
-			break;
-		case I2O_LAN_100BASE_TX:
-			len += sprintf(buf+len, "100BASE-TX\n");
-			break;
-		case I2O_LAN_100BASE_FX:
-			len += sprintf(buf+len, "100BASE-FX\n");
-			break;
-		case I2O_LAN_100BASE_T4:
-			len += sprintf(buf+len, "100BASE-T4\n");
-			break;
-		case I2O_LAN_1000BASE_SX:
-			len += sprintf(buf+len, "1000BASE-SX\n");
-			break;
-		case I2O_LAN_1000BASE_LX:
-			len += sprintf(buf+len, "1000BASE-LX\n");
-			break;
-		case I2O_LAN_1000BASE_CX:
-			len += sprintf(buf+len, "1000BASE-CX\n");
-			break;
-		case I2O_LAN_1000BASE_T:
-			len += sprintf(buf+len, "1000BASE-T\n");
-			break;
-		case I2O_LAN_100VG_ETHERNET:
-			len += sprintf(buf+len, "100VG-ETHERNET\n");
-			break;
-		case I2O_LAN_100VG_TR:
-			len += sprintf(buf+len, "100VG-TOKEN RING\n");
-			break;
-		case I2O_LAN_4MBIT:
-			len += sprintf(buf+len, "4MBIT TOKEN RING\n");
-			break;
-		case I2O_LAN_16MBIT:
-			len += sprintf(buf+len, "16 Mb Token Ring\n");
-			break;
-		case I2O_LAN_125MBAUD:
-			len += sprintf(buf+len, "125 MBAUD FDDI\n");
-			break;
-		case I2O_LAN_POINT_POINT:
-			len += sprintf(buf+len, "Point-to-point\n");
-			break;
-		case I2O_LAN_ARB_LOOP:
-			len += sprintf(buf+len, "Arbitrated loop\n");
-			break;
-		case I2O_LAN_PUBLIC_LOOP:
-			len += sprintf(buf+len, "Public loop\n");
-			break;
-		case I2O_LAN_FABRIC:
-			len += sprintf(buf+len, "Fabric\n");
-			break;
-		case I2O_LAN_EMULATION:
-			len += sprintf(buf+len, "Emulation\n");
-			break;
-		case I2O_LAN_OTHER:
-			len += sprintf(buf+len, "Other\n");
-			break;
-		case I2O_LAN_DEFAULT:
-			len += sprintf(buf+len, "HW default\n");
-			break;
-		default:
-			len += sprintf(buf+len, "\n");
-			break;
-		}
+		len += sprintf(buf+len, "Connector type target  : %s\n",
+			       i2o_get_connector_type(work32[7]));
+		len += sprintf(buf+len, "Connection type target : %s\n",
+			       i2o_get_connection_type(work32[8]));
 	}
+
 	spin_unlock(&i2o_proc_lock);
 	return len;
 }
 
-#if 0
 /* LAN group 0006h - Alternate address (table) */
 int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len,
 			       int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
-	static u8 work8[32];
-	static u32 field32[2];
+	static u32 field32[64];
 	static u8 *field8 = (u8 *)field32;
+	static u16 *field16 = (u16 *)field32;
 	int token;
+	int i;
 
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
-	token = i2o_query_table_polled(d->controller, d->id, &work8, 32,
-				       0x0006, 0, field32, 8);
-	switch (token) {
-	case -ETIMEDOUT:
-		len += sprintf(buf, "Timeout reading table.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-		break;
-	case -ENOMEM:
-		len += sprintf(buf, "No free memory to read the table.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-		break;
-	case -EBADR:
-		len += sprintf(buf, "Error reading field.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-		break;
-	default:
-		break;
-	}
+	token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+			d->controller, d->id, proc_context, 0x0006, -1, 
+			NULL, 0, &field32, sizeof(field32),
+			&i2o_proc_token);
+
+	if (token<0)
+		switch (token) {
+		case -ETIMEDOUT:
+			len += sprintf(buf, "Timeout reading table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		case -ENOMEM:
+			len += sprintf(buf, "No free memory to read the table.\n");
+			spin_unlock(&i2o_proc_lock);
+			return len;
+			break;
+		default:
+			len += sprintf(buf, "Error reading field. BlockStatus %d\n",
+				       token);
+			spin_unlock(&i2o_proc_lock);
+			return len;
+		}
 
-	len += sprintf(buf, "Alternate Address: "
-		       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                       field8[0],field8[1],field8[2],field8[3],
-                       field8[4],field8[5],field8[6],field8[7]);
+	len += sprintf(buf,"RowCount=%d, MoreFlag=%d\n", field16[0],
+		       field16[1]);
+
+	field8=(u8 *)&field16[2];
+
+	for(i=0; i<field16[0]; i++, field8+=8)
+	{
+		len += sprintf(buf+len, "Alternate address[%d]: "
+			       "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+			       i,
+			       field8[0], field8[1], field8[2],
+			       field8[3], field8[4], field8[5],
+			       field8[6], field8[7]);
+	}
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
 }
-#endif
+
 
 /* LAN group 0007h - Transmit info (scalar) */
 int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, 
-				    int *eof, void *data)
+			      int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[10];
+	static u32 work32[8];
 	int token;
 
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
 	token = i2o_query_scalar(d->controller, d->id, proc_context, 
-				 0x0007, -1, &work32, 8, &i2o_proc_token);
+				 0x0007, -1, &work32, 8*4, &i2o_proc_token);
 	if(token < 0)
 	{
 		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
@@ -1957,12 +2354,12 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Max SG Elements per packet: %d\n", work32[0]);
-	len += sprintf(buf+len, "Max SG Elements per chain: %d\n", work32[1]);
-	len += sprintf(buf+len, "Max outstanding packets: %d\n", work32[2]);
-	len += sprintf(buf+len, "Max packets per request: %d\n", work32[3]);
+	len += sprintf(buf,     "Max SG Elements per packet : %d\n", work32[0]);
+	len += sprintf(buf+len, "Max SG Elements per chain  : %d\n", work32[1]);
+	len += sprintf(buf+len, "Max outstanding packets    : %d\n", work32[2]);
+	len += sprintf(buf+len, "Max packets per request    : %d\n", work32[3]);
 
-	len += sprintf(buf+len, "Tx modes:\n");
+	len += sprintf(buf+len, "Tx modes :\n");
 	if(work32[4]&0x00000002)
 		len += sprintf(buf+len, "    No DA in SGL\n");
 	if(work32[4]&0x00000004)
@@ -1974,25 +2371,25 @@
 	if(work32[4]&0x00000020)
 		len += sprintf(buf+len, "    RIF insertion\n");
 	if(work32[4]&0x00000100)
-		len += sprintf(buf+len, "    IPv4 Checksum\n");
+		len += sprintf(buf+len, "    IPv4 checksum\n");
 	if(work32[4]&0x00000200)
-		len += sprintf(buf+len, "    TCP Checksum\n");
+		len += sprintf(buf+len, "    TCP checksum\n");
 	if(work32[4]&0x00000400)
-		len += sprintf(buf+len, "    UDP Checksum\n");
+		len += sprintf(buf+len, "    UDP checksum\n");
 	if(work32[4]&0x00000800)
-		len += sprintf(buf+len, "    RSVP Checksum\n");
+		len += sprintf(buf+len, "    RSVP checksum\n");
 	if(work32[4]&0x00001000)
-		len += sprintf(buf+len, "    ICMP Checksum\n");
+		len += sprintf(buf+len, "    ICMP checksum\n");
 	if (d->i2oversion == 0x00) {
 		if(work32[4]&0x00008000)
-			len += sprintf(buf+len, "    Loopback Enabled\n");
+			len += sprintf(buf+len, "    Loopback enabled\n");
 		if(work32[4]&0x00010000)
-			len += sprintf(buf+len, "    Loopback Suppression Enabled\n");
+			len += sprintf(buf+len, "    Loopback suppression enabled\n");
 	} else {
 		if(work32[4]&0x00010000)
-			len += sprintf(buf+len, "    Loopback Enabled\n");
+			len += sprintf(buf+len, "    Loopback enabled\n");
 		if(work32[4]&0x00020000)
-			len += sprintf(buf+len, "    Loopback Suppression Enabled\n");
+			len += sprintf(buf+len, "    Loopback suppression enabled\n");
 	}
 
 	spin_unlock(&i2o_proc_lock);
@@ -2001,17 +2398,17 @@
 
 /* LAN group 0008h - Receive info (scalar) */
 int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, 
-				    int *eof, void *data)
+			      int *eof, void *data)
 {
 	struct i2o_device *d = (struct i2o_device*)data;
-	static u32 work32[10];
+	static u32 work32[8];
 	int token;
 
 	spin_lock(&i2o_proc_lock);	
 	len = 0;
 
 	token = i2o_query_scalar(d->controller, d->id, proc_context, 
-				 0x0008, -1, &work32, 8, &i2o_proc_token);
+				 0x0008, -1, &work32, 8*4, &i2o_proc_token);
 	if(token < 0)
 	{
 		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
@@ -2019,14 +2416,14 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Max size of chain element: %d\n", work32[0]);
-	len += sprintf(buf+len, "Max number of buckets: %d\n", work32[1]);
+	len += sprintf(buf,"Max size of chain element : %d\n", work32[0]);
+	len += sprintf(buf+len, "Max number of buckets     : %d\n", work32[1]);
 
 	if (d->i2oversion > 0x00) { /* not in 1.5 */
-		len += sprintf(buf+len, "Rx modes: %d\n", work32[2]);
-		len += sprintf(buf+len, "RxMaxBucketsReply: %d\n", work32[3]);
-		len += sprintf(buf+len, "RxMaxPacketsPerBuckets: %d\n", work32[4]);
-		len += sprintf(buf+len, "RxMaxPostBuckets: %d\n", work32[5]);
+		len += sprintf(buf+len, "RxModes                   : %d\n", work32[2]);
+		len += sprintf(buf+len, "RxMaxBucketsReply         : %d\n", work32[3]);
+		len += sprintf(buf+len, "RxMaxPacketsPerBuckets    : %d\n", work32[4]);
+		len += sprintf(buf+len, "RxMaxPostBuckets          : %d\n", work32[5]);
 	}
 
 	spin_unlock(&i2o_proc_lock);
@@ -2054,15 +2451,63 @@
 		return len;
 	}
 
-	len += sprintf(buf, "Tx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[0]));
-	len += sprintf(buf+len, "Tx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "Rx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-	len += sprintf(buf+len, "Rx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "Tx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-	len += sprintf(buf+len, "Rx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[5]));
-	len += sprintf(buf+len, "Rx dropped: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-	len += sprintf(buf+len, "Adapter resets: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-	len += sprintf(buf+len, "Adapter suspends: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
+	len += sprintf(buf,     "Tx packets       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf+len, "Tx bytes         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "Rx packets       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "Rx bytes         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "Tx errors        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "Rx errors        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[5]));
+	len += sprintf(buf+len, "Rx dropped       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "Adapter resets   : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[8]));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+
+/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */
+int i2o_proc_read_lan_supp_opt_stats(char *buf, char **start, off_t offset,
+				     int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[4];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->id, proc_context, 
+				 0x0180, -1, &work64, 4*8, &i2o_proc_token);
+	if(token < 0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	if (d->i2oversion == 0x00)
+		len += sprintf(buf, "Supported stats : " FMT_U64_HEX " \n",
+			       U64_VAL(&work64[0]));
+	else
+	{
+		len += sprintf(buf, "Supported stats (0182h) : " FMT_U64_HEX " \n",
+			       U64_VAL(&work64[1]));
+		len += sprintf(buf, "Supported stats (0183h) : " FMT_U64_HEX " \n",
+			       U64_VAL(&work64[2]));
+		len += sprintf(buf, "Supported stats (0184h) : " FMT_U64_HEX " \n",
+			       U64_VAL(&work64[3]));
+	}
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -2091,15 +2536,24 @@
 		return len;
 	}
 
-	len += sprintf(buf, "TxRetryCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0]));
-	len += sprintf(buf+len, "DirectedBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "DirectedPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-	len += sprintf(buf+len, "MulticastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "MulticastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-	len += sprintf(buf+len, "BroadcastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[5]));
-	len += sprintf(buf+len, "BroadcastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-	len += sprintf(buf+len, "TotalGroupAddrTxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-	len += sprintf(buf+len, "TotalTxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
+	len += sprintf(buf,     "TxRetryCount           : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf+len, "DirectedBytesTx        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "DirectedPacketsTx      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "MulticastBytesTx       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "MulticastPacketsTx     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "BroadcastBytesTx       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[5]));
+	len += sprintf(buf+len, "BroadcastPacketsTx     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "TotalGroupAddrTxCount  : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "TotalTxPacketsTooShort : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[8]));
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -2127,22 +2581,206 @@
 		return len;
 	}
 
-	len += sprintf(buf, "ReceiveCRCErrorCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0]));
-	len += sprintf(buf+len, "DirectedBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "DirectedPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-	len += sprintf(buf+len, "MulticastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "MulticastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-	len += sprintf(buf+len, "BroadcastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[5]));
-	len += sprintf(buf+len, "BroadcastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-	len += sprintf(buf+len, "TotalGroupAddrRxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-	len += sprintf(buf+len, "TotalRxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
-	len += sprintf(buf+len, "TotalRxPacketsTooLong: " FMT_U64_HEX "\n", U64_VAL(&work64[9]));
-	len += sprintf(buf+len, "TotalRuntPacketsReceived: " FMT_U64_HEX "\n", U64_VAL(&work64[10]));
+	len += sprintf(buf,     "ReceiveCRCErrorCount     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf+len, "DirectedBytesRx          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "DirectedPacketsRx        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "MulticastBytesRx         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "MulticastPacketsRx       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "BroadcastBytesRx         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[5]));
+	len += sprintf(buf+len, "BroadcastPacketsRx       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "TotalGroupAddrRxCount    : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "TotalRxPacketsTooShort   : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[8]));
+	len += sprintf(buf+len, "TotalRxPacketsTooLong    : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[9]));
+	len += sprintf(buf+len, "TotalRuntPacketsReceived : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[10]));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0200h - Required Ethernet Statistics (scalar) */
+int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset,
+				int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[8];
+	int token;
+
+
+	spin_lock(&i2o_proc_lock);
+	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->id, proc_context, 
+				 0x0200, -1, &work64, 8*8, &i2o_proc_token);
+	if(token < 0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "Rx alignment errors    : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf+len, "Tx one collisions      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "Tx multicollisions     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "Tx deferred            : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "Tx late collisions     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "Tx max collisions      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[5]));
+	len += sprintf(buf+len, "Tx carrier lost        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0280h - Supported Ethernet Historical Statistics (scalar) */
+int i2o_proc_read_lan_supp_eth_stats(char *buf, char **start, off_t offset,
+				     int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[1];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->id, proc_context, 
+				 0x0280, -1, &work64, 8, &i2o_proc_token);
+	if(token < 0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf, "Supported stats : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
+
+/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */
+int i2o_proc_read_lan_opt_eth_stats(char *buf, char **start, off_t offset,
+				    int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[3];
+	int token;
+
+	spin_lock(&i2o_proc_lock);	
+
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->id, proc_context, 
+				 0x0281, -1, &work64, 3*8, &i2o_proc_token);
+	if(token < 0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf, "Rx overrun           : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf, "Tx underrun          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf, "Tx heartbeat failure : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
 }
 
+/* LAN group 0300h - Required Token Ring Statistics (scalar) */
+int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
+			       int len, int *eof, void *data)
+{
+	struct i2o_device *d = (struct i2o_device*)data;
+	static u64 work64[13];
+	int token;
+
+	static char *ring_status[] =
+	{
+		"",
+		"",
+		"",
+		"",
+		"",
+		"Ring Recovery",
+		"Single Station",
+		"Counter Overflow",
+		"Remove Received",
+		"",
+		"Auto-Removal Error 1",
+		"Lobe Wire Fault",
+		"Transmit Beacon",
+		"Soft Error",
+		"Hard Error",
+		"Signal Loss"
+	};
+
+	spin_lock(&i2o_proc_lock);
+	
+	len = 0;
+
+	token = i2o_query_scalar(d->controller, d->id, proc_context, 
+				 0x0300, -1, &work64, 13*8, &i2o_proc_token);
+	if(token < 0)
+	{
+		len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+		spin_unlock(&i2o_proc_lock);
+		return len;
+	}
+
+	len += sprintf(buf,     "LineErrors          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[0]));
+	len += sprintf(buf+len, "LostFrames          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "ACError             : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "TxAbortDelimiter    : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "BursErrors          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "FrameCopiedErrors   : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[5]));
+	len += sprintf(buf+len, "FrequencyErrors     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "InternalErrors      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "LastRingStatus      : %s\n", ring_status[work64[8]]);
+	len += sprintf(buf+len, "TokenError          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[9]));
+	len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[10]));
+	len += sprintf(buf+len, "LastRingID          : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[11]));
+	len += sprintf(buf+len, "LastBeaconType      : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[12]));
+
+	spin_unlock(&i2o_proc_lock);
+	return len;
+}
 
 /* LAN group 0400h - Required FDDI Statistics (scalar) */
 int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
@@ -2208,23 +2846,31 @@
 		return len;
 	}
 
-	len += sprintf(buf, "ConfigurationState: %s\n", conf_state[work64[0]]);
-	len += sprintf(buf+len, "UpstreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[1]));
-	len += sprintf(buf+len, "DownStreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[2]));
-	len += sprintf(buf+len, "FrameErrors: " FMT_U64_HEX "\n", U64_VAL(&work64[3]));
-	len += sprintf(buf+len, "FramesLost: " FMT_U64_HEX "\n", U64_VAL(&work64[4]));
-	len += sprintf(buf+len, "RingMgmtState: %s\n", ring_state[work64[5]]);
-	len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n", U64_VAL(&work64[6]));
-	len += sprintf(buf+len, "LEMRejects: " FMT_U64_HEX "\n", U64_VAL(&work64[7]));
-	len += sprintf(buf+len, "LEMCount: " FMT_U64_HEX "\n", U64_VAL(&work64[8]));
-	len += sprintf(buf+len, "LConnectionState: %s\n", link_state[work64[9]]);
+	len += sprintf(buf,     "ConfigurationState : %s\n", conf_state[work64[0]]);
+	len += sprintf(buf+len, "UpstreamNode       : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[1]));
+	len += sprintf(buf+len, "DownStreamNode     : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[2]));
+	len += sprintf(buf+len, "FrameErrors        : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[3]));
+	len += sprintf(buf+len, "FramesLost         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[4]));
+	len += sprintf(buf+len, "RingMgmtState      : %s\n", ring_state[work64[5]]);
+	len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[6]));
+	len += sprintf(buf+len, "LEMRejects         : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[7]));
+	len += sprintf(buf+len, "LEMCount           : " FMT_U64_HEX "\n",
+		       U64_VAL(&work64[8]));
+	len += sprintf(buf+len, "LConnectionState   : %s\n",
+		       link_state[work64[9]]);
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
 }
 
-static int i2o_proc_create_entries(void *data,
-	i2o_proc_entry *pentry, struct proc_dir_entry *parent)
+static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry,
+				   struct proc_dir_entry *parent)
 {
 	struct proc_dir_entry *ent;
 	
@@ -2245,7 +2891,7 @@
 }
 
 static void i2o_proc_remove_entries(i2o_proc_entry *pentry, 
-	struct proc_dir_entry *parent)
+				    struct proc_dir_entry *parent)
 {
 	while(pentry->name != NULL)
 	{
@@ -2255,7 +2901,7 @@
 }
 
 static int i2o_proc_add_controller(struct i2o_controller *pctrl, 
-	struct proc_dir_entry *root )
+				   struct proc_dir_entry *root )
 {
 	struct proc_dir_entry *dir, *dir1;
 	struct i2o_device *dev;
@@ -2291,6 +2937,23 @@
 			break;
 		case I2O_CLASS_LAN:
 			i2o_proc_create_entries(dev, lan_entries, dir1);
+			switch(dev->subclass)
+			{
+			case I2O_LAN_ETHERNET:
+				i2o_proc_create_entries(dev, lan_eth_entries,
+							dir1);
+				break;
+			case I2O_LAN_FDDI:
+				i2o_proc_create_entries(dev, lan_fddi_entries,
+							dir1);
+				break;
+			case I2O_LAN_TR:
+				i2o_proc_create_entries(dev, lan_tr_entries,
+							dir1);
+				break;
+			default:
+				break;
+			}
 			break;
 		default:
 			break;
@@ -2301,17 +2964,58 @@
 }
 
 static void i2o_proc_remove_controller(struct i2o_controller *pctrl, 
-	struct proc_dir_entry *parent)
+				       struct proc_dir_entry *parent)
 {
 	char buff[10];
+	char dev_id[10];
+	struct proc_dir_entry *de;
+	struct i2o_device *dev;
 
-	sprintf(buff, "iop%d", pctrl->unit);
+	/* Remove unused device entries */
+	for(dev=pctrl->devices; dev; dev=dev->next)
+	{
+		de=dev->proc_entry;
+		sprintf(dev_id, "%0#5x", dev->id);
 
-	i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
+		/* Would it be safe to remove _files_ even if they are in use? */
+		if((de) && (!de->count))
+		{
+			i2o_proc_remove_entries(generic_dev_entries, de);
 
-	remove_proc_entry(buff, parent);
+			switch(dev->class)
+			{
+			case I2O_CLASS_SCSI_PERIPHERAL:
+			case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+				i2o_proc_remove_entries(rbs_dev_entries, de);
+				break;
+			case I2O_CLASS_LAN:
+				i2o_proc_remove_entries(lan_entries, de);
+				switch(dev->subclass)
+				{
+				case I2O_LAN_ETHERNET:
+					i2o_proc_remove_entries(lan_eth_entries, de);
+					break;
+				case I2O_LAN_FDDI:
+					i2o_proc_remove_entries(lan_fddi_entries, de);
+					break;
+				case I2O_LAN_TR:
+					i2o_proc_remove_entries(lan_tr_entries, de);
+					break;
+				}
+			}
+			remove_proc_entry(dev_id, parent);
+		}
+	}
 
-	pctrl->proc_entry = NULL;
+	if(!pctrl->proc_entry->count)
+	{
+		sprintf(buff, "iop%d", pctrl->unit);
+
+		i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
+
+		remove_proc_entry(buff, parent);
+		pctrl->proc_entry = NULL;
+	}
 }
 
 static int create_i2o_procfs(void)
@@ -2327,7 +3031,10 @@
 	{
 		pctrl = i2o_find_controller(i);
 		if(pctrl)
+		{
 			i2o_proc_add_controller(pctrl, i2o_proc_dir_root);
+			i2o_unlock_controller(pctrl);
+		}
 	};
 
 	return 0;
@@ -2345,19 +3052,25 @@
 	{
 		pctrl = i2o_find_controller(i);
 		if(pctrl)
+		{
 			i2o_proc_remove_controller(pctrl, i2o_proc_dir_root);
+			i2o_unlock_controller(pctrl);
+		}
 	};
 
-	remove_proc_entry("i2o", 0);
+	if(!i2o_proc_dir_root->count)
+		remove_proc_entry("i2o", 0);
+	else
+		return -1;
+
 	return 0;
 }
 		
 #ifdef MODULE
+#define i2o_proc_init init_module
+#endif
 
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("I2O procfs Handler");
-
-int init_module(void)
+__init int i2o_proc_init(void)
 {
 	if(create_i2o_procfs())
 		return -EBUSY;
@@ -2372,6 +3085,12 @@
 
 	return 0;
 }
+
+#ifdef MODULE
+
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("I2O procfs Handler");
 
 void cleanup_module(void)
 {
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_proc.h linux/drivers/i2o/i2o_proc.h
--- v2.3.9/linux/drivers/i2o/i2o_proc.h	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_proc.h	Mon Jul  5 20:09:40 1999
@@ -32,110 +32,5 @@
 	u8 reserved;
 	u8 req_status;
 } i2o_mult_reply_msg, *pi2o_mult_reply_msg;
-
-/**************************************************************************
- * HRT related constants and structures
- **************************************************************************/
-#define    I2O_BUS_LOCAL                               0
-#define    I2O_BUS_ISA                                 1
-#define    I2O_BUS_EISA                                2
-#define    I2O_BUS_MCA                                 3
-#define    I2O_BUS_PCI                                 4
-#define    I2O_BUS_PCMCIA                              5
-#define    I2O_BUS_NUBUS                               6
-#define    I2O_BUS_CARDBUS                             7
-#define    I2O_BUS_UNKNOWN                            0x80
-
-typedef struct _i2o_pci_bus {
-	u8 PciFunctionNumber;
-	u8 PciDeviceNumber;
-	u8 PciBusNumber;
-	u8 reserved;
-	u16 PciVendorID;
-	u16 PciDeviceID;
-} i2o_pci_bus, *pi2o_pci_bus;
-
-typedef struct _i2o_local_bus {
-	u16 LbBaseIOPort;
-	u16 reserved;
-	u32 LbBaseMemoryAddress;
-} i2o_local_bus, *pi2o_local_bus;
-
-typedef struct _i2o_isa_bus {
-	u16 IsaBaseIOPort;
-	u8 CSN;
-	u8 reserved;
-	u32 IsaBaseMemoryAddress;
-} i2o_isa_bus, *pi2o_isa_bus;
-
-/* I2O_EISA_BUS_INFO  */
-typedef struct _i2o_eisa_bus_info {
-	u16 EisaBaseIOPort;
-	u8 reserved;
-	u8 EisaSlotNumber;
-	u32 EisaBaseMemoryAddress;
-} i2o_eisa_bus, *pi2o_eisa_bus;
-
-typedef struct _i2o_mca_bus {
-	u16 McaBaseIOPort;
-	u8 reserved;
-	u8 McaSlotNumber;
-	u32 McaBaseMemoryAddress;
-} i2o_mca_bus, *pi2o_mca_bus;
-
-typedef struct _i2o_other_bus {
-	u16 BaseIOPort;
-	u16 reserved;
-	u32 BaseMemoryAddress;
-} i2o_other_bus, *pi2o_other_bus;
-
-
-typedef struct _i2o_hrt_entry {
-	u32 adapter_id;
-	u32 parent_tid:12;
-	u32 state:4;
-	u32 bus_num:8;
-	u32 bus_type:8;
-	union {
-		i2o_pci_bus pci_bus;
-		i2o_local_bus local_bus;
-		i2o_isa_bus isa_bus;
-		i2o_eisa_bus eisa_bus;
-		i2o_mca_bus mca_bus;
-		i2o_other_bus other_bus;
-	} bus;
-} i2o_hrt_entry, *pi2o_hrt_entry;
-
-typedef struct _i2o_hrt {
-	u16 num_entries;
-	u8 entry_len;
-	u8 hrt_version;
-	u32 change_ind;
-	i2o_hrt_entry hrt_entry[1];
-} i2o_hrt, *pi2o_hrt;
-
-typedef struct _i2o_lct_entry {
-	u32 entry_size:16;
-	u32 tid:12;
-	u32 reserved:4;
-	u32 change_ind;
-	u32 device_flags;
-	u32 class_id;
-	u32 sub_class;
-	u32 user_tid:12;
-	u32 parent_tid:12;
-	u32 bios_info:8;
-	u8 identity_tag[8];
-	u32 event_capabilities;
-} i2o_lct_entry, *pi2o_lct_entry;
-
-typedef struct _i2o_lct {
-	u32 table_size:16;
-	u32 boot_tid:12;
-	u32 lct_ver:4;
-	u32 iop_flags;
-	u32 current_change_ind;
-	i2o_lct_entry lct_entry[1];
-} i2o_lct, *pi2o_lct;
-
+   
 #endif				/* i2oproc_h */
diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- v2.3.9/linux/drivers/i2o/i2o_scsi.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_scsi.c	Mon Jul  5 20:35:18 1999
@@ -26,6 +26,9 @@
  *	Fixes:
  *		Steve Ralston	:	Scatter gather now works
  *
+ *	To Do
+ *		64bit cleanups
+ *		Fix the resource management problems.
  */
 
 #include <linux/module.h>
@@ -37,7 +40,6 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -83,6 +85,7 @@
 /*
  *	SG Chain buffer support...
  */
+
 #define SG_MAX_FRAGS		64
 
 /*
@@ -204,9 +207,12 @@
 	}
 			
 	
-	/* Low byte is the adapter status, next is the device */
-	as=(u8)m[4]; 
-	ds=(u8)(m[4]>>8);
+	/*
+	 *	Low byte is device status, next is adapter status,
+	 *	(then one byte reserved), then request status.
+	 */
+	ds=(u8)m[4]; 
+	as=(u8)(m[4]>>8);
 	st=(u8)(m[4]>>24);
 	
 	dprintk(("i2o got a scsi reply %08X: ", m[0]));
@@ -264,10 +270,10 @@
 
 		dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
 			
-		if (ds == 0x0E) 
+		if (as == 0x0E) 
 			/* SCSI Reset */
 			current_command->result = DID_RESET << 16;
-		else if (ds == 0x0F)
+		else if (as == 0x0F)
 			current_command->result = DID_PARITY << 16;
 		else
 			current_command->result = DID_ERROR << 16;
@@ -433,7 +439,6 @@
 			  )
 				continue;
 		
-//			printk("Found a controller.\n");	
 			shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host));
 			save_flags(flags);
 			cli();
@@ -443,7 +448,6 @@
 			shpnt->irq = 0;
 			shpnt->this_id = /* Good question */15;
 			restore_flags(flags);
-//			printk("Scanning I2O port %d.\n", d->id);
 			i2o_scsi_init(c, d, shpnt);
 			count++;
 		}
@@ -534,25 +538,12 @@
 	int direction;
 	int scsidir;
 	u32 len;
+	u32 reqlen;
+	u32 tag;
 	
 	static int max_qd = 1;
 	
 	/*
-	 *	The scsi layer should be handling this stuff
-	 */
-
-	if(is_dir_out(SCpnt))
-	{
-		direction=0x04000000;
-		scsidir=0x80000000;
-	}
-	else
-	{
-		scsidir=0x40000000;
-		direction=0x00000000;
-	}
-	
-	/*
 	 *	Do the incoming paperwork
 	 */
 	 
@@ -604,13 +595,45 @@
 	 *	Put together a scsi execscb message
 	 */
 	
+	len = SCpnt->request_bufflen;
+	direction = 0x00000000;			// SGL IN  (osm<--iop)
+	
+	/*
+	 *	The scsi layer should be handling this stuff
+	 */
+	
+	scsidir = 0x00000000;			// DATA NO XFER
+	if(len)
+	{
+		if(is_dir_out(SCpnt))
+		{
+			direction=0x04000000;	// SGL OUT  (osm-->iop)
+			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
+		}
+		else
+		{
+			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+		}
+	}
+	
 	msg[1] = I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid;
 	msg[2] = scsi_context;		/* So the I2O layer passes to us */
 	/* Sorry 64bit folks. FIXME */
 	msg[3] = (u32)SCpnt;		/* We want the SCSI control block back */
-	/* Direction, disconnect ok, no tagging (yet) */
-	msg[4] = scsidir|(1<<29)|SCpnt->cmd_len;
 
+	/* LSI_920_PCI_QUIRK
+	 *
+	 *	Intermittant observations of msg frame word data corruption
+	 *	observed on msg[4] after:
+	 *	  WRITE, READ-MODIFY-WRITE
+	 *	operations.  19990606 -sralston
+	 *
+	 *	(Hence we build this word via tag. Its good practice anyway
+	 *	 we don't want fetches over PCI needlessly)
+	 */
+
+	tag=0;
+	
 	/*
 	 *	Attach tags to the devices
 	 */	
@@ -623,25 +646,24 @@
 		 */
 		if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ))
 		{
-			msg[4]|=(1<<23)|(1<<24);
+			tag=0x01800000;		/* ORDERED! */
 			hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies;
 		}
-		else switch(SCpnt->tag)
+		else
 		{
-			case SIMPLE_QUEUE_TAG:
-				msg[4]|=(1<<23);
-				break;
-			case HEAD_OF_QUEUE_TAG:
-				msg[4]|=(1<<24);
-				break;
-			case ORDERED_QUEUE_TAG:
-				msg[4]|=(1<<23)|(1<<24);
-				break;
-			default:
-				msg[4]|=(1<<23);
+			/* Hmmm...  I always see value of 0 here,
+			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
+			 */
+			if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
+				tag=0x01000000;
+			else if(SCpnt->tag == ORDERED_QUEUE_TAG)
+				tag=0x01800000;
 		}
 	}
 
+	/* Direction, disconnect ok, tag, CDBLen */
+	msg[4] = scsidir|0x20000000|SCpnt->cmd_len|tag;
+
 	mptr=msg+5;
 
 	/* 
@@ -652,7 +674,7 @@
 	mptr+=4;
 	lenptr=mptr++;		/* Remember me - fill in when we know */
 	
-			
+	reqlen = 12;		// SINGLE SGE
 	/*
 	 *	Now fill in the SGList and command 
 	 *
@@ -664,21 +686,22 @@
 	if(SCpnt->use_sg)
 	{
 		struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
+		int chain = 0;
 		
 		if((sg_max_frags > 11) && (SCpnt->use_sg > 11))
 		{
+			chain = 1;
 			/*
 			 *	Need to chain!
 			 */
-			SCpnt->host_scribble = (void*)(sg_chain_pool + sg_chain_tag);
 			*mptr++=direction|0xB0000000|(SCpnt->use_sg*2*4);
-			*mptr=virt_to_bus(SCpnt->host_scribble);
-			mptr = (u32*)SCpnt->host_scribble;
+			*mptr=virt_to_bus(sg_chain_pool + sg_chain_tag);
+			mptr = (u32*)(sg_chain_pool + sg_chain_tag);
 			if (SCpnt->use_sg > max_sg_len)
 			{
 				max_sg_len = SCpnt->use_sg;
 				printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n",
-					SCpnt, SCpnt->use_sg, (chain_buf*)SCpnt->host_scribble-sg_chain_pool);
+					SCpnt, SCpnt->use_sg, sg_chain_tag);
 			}
 			if ( ++sg_chain_tag == SG_MAX_BUFS )
 				sg_chain_tag = 0;
@@ -693,7 +716,15 @@
 			*mptr++=virt_to_bus(sg->address);
 			sg++;
 		}
-		mptr[-2]|=0xC0000000;	/* End of List and block */
+
+		/* Make this an end of list. Again evade the 920 bug and
+		   unwanted PCI read traffic */
+		
+		mptr[-2]=direction|0xD0000000|(sg-1)->length;
+		
+		if(!chain)
+			reqlen = mptr - msg;
+		
 		*lenptr=len;
 		if(len != SCpnt->underflow)
 			printk("Cmd len %08X Cmd underflow %08X\n",
@@ -703,19 +734,23 @@
 	{
 		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
 				SCpnt->request_bufflen));
-		*mptr++=0xD0000000|direction|SCpnt->request_bufflen;
-		*mptr++=virt_to_bus(SCpnt->request_buffer);
 		*lenptr = len = SCpnt->request_bufflen;
-		/* No transfer ? - fix up the request */
 		if(len == 0)
-			msg[4]&=~0xC0000000;
+		{
+			reqlen = 9;
+		}
+		else
+		{
+			*mptr++=0xD0000000|direction|SCpnt->request_bufflen;
+			*mptr++=virt_to_bus(SCpnt->request_buffer);
+		}
 	}
 	
 	/*
 	 *	Stick the headers on 
 	 */
 
-	msg[0] = (mptr-msg)<<16 | SGL_OFFSET_10;
+	msg[0] = reqlen<<16 | SGL_OFFSET_10;
 	
 	/* Queue the message */
 	i2o_post_message(c,m);
@@ -757,7 +792,7 @@
 	u32 m;
 	int tid;
 	
-	printk("i2o_scsi_abort\n");
+	printk("i2o_scsi: Aborting command block.\n");
 	
 	host = SCpnt->host;
 	hostdata = (struct i2o_scsi_host *)host->hostdata;
@@ -790,8 +825,6 @@
 	wmb();
 	i2o_post_message(c,m);
 	wmb();
-//	SCpnt->result = DID_RESET << 16;
-//	SCpnt->scsi_done(SCpnt);
 	return SCSI_ABORT_PENDING;
 }
 
@@ -804,12 +837,12 @@
 	u32 m;
 	u32 *msg;
 
-	printk("i2o_scsi_reset\n");
-	
 	/*
 	 *	Find the TID for the bus
 	 */
 
+	printk("i2o_scsi: Attempting to reset the bus.\n");
+	
 	host = SCpnt->host;
 	hostdata = (struct i2o_scsi_host *)host->hostdata;
 	tid = hostdata->bus_task;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- v2.3.9/linux/drivers/isdn/avmb1/capidrv.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/avmb1/capidrv.c	Mon Jul  5 20:09:40 1999
@@ -1386,13 +1386,14 @@
 			handle_data(&s_cmsg, skb);
 			continue;
 		}
-		kfree_skb(skb);
 		if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
 			handle_controller(&s_cmsg);
 		else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
 			handle_plci(&s_cmsg);
 		else
 			handle_ncci(&s_cmsg);
+
+		kfree_skb(skb);
 	}
 }
 
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c
--- v2.3.9/linux/drivers/isdn/hisax/amd7930.c	Wed Apr  1 16:20:57 1998
+++ linux/drivers/isdn/hisax/amd7930.c	Tue Jul  6 19:05:48 1999
@@ -747,8 +747,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init 
+setup_amd7930(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c
--- v2.3.9/linux/drivers/isdn/hisax/asuscom.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/asuscom.c	Tue Jul  6 19:05:48 1999
@@ -334,8 +334,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init 
+setup_asuscom(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- v2.3.9/linux/drivers/isdn/hisax/avm_a1.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/avm_a1.c	Tue Jul  6 19:05:48 1999
@@ -234,8 +234,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_avm_a1(struct IsdnCard *card))
+int __init 
+setup_avm_a1(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.3.9/linux/drivers/isdn/hisax/config.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/config.c	Tue Jul  6 19:05:48 1999
@@ -442,8 +442,8 @@
 #ifdef MODULE
 #define HiSax_init init_module
 #else
-__initfunc(void
-HiSax_setup(char *str, int *ints))
+void __init 
+HiSax_setup(char *str, int *ints)
 {
 	int i, j, argc;
 
@@ -1236,8 +1236,8 @@
 }
 
 
-__initfunc(int
-HiSax_init(void))
+int __init 
+HiSax_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- v2.3.9/linux/drivers/isdn/hisax/diva.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/diva.c	Tue Jul  6 19:05:48 1999
@@ -459,8 +459,8 @@
 static 	struct pci_dev *dev_diva __initdata = NULL;
 static 	struct pci_dev *dev_diva_u __initdata = NULL;
 
-__initfunc(int
-setup_diva(struct IsdnCard *card))
+int __init 
+setup_diva(struct IsdnCard *card)
 {
 	int bytecnt;
 	u_char val;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/foreign.c linux/drivers/isdn/hisax/foreign.c
--- v2.3.9/linux/drivers/isdn/hisax/foreign.c	Mon Mar 15 16:11:30 1999
+++ linux/drivers/isdn/hisax/foreign.c	Tue Jul  6 19:05:48 1999
@@ -744,8 +744,8 @@
 extern struct foreign_interface dbri_foreign_interface;
 #endif
 
-__initfunc(int
-setup_foreign(struct IsdnCard *card))
+int __init 
+setup_foreign(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- v2.3.9/linux/drivers/isdn/hisax/hfc_2bds0.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Tue Jul  6 19:05:48 1999
@@ -1166,8 +1166,8 @@
 #endif
 }
 
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int __init 
+*init_send_hfcd(int cnt)
 {
 	int i, *send;
 
@@ -1181,8 +1181,8 @@
 	return(send);
 }
 
-__initfunc(void
-init2bds0(struct IsdnCardState *cs))
+void __init 
+init2bds0(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcd;
 	cs->dbusytimer.function = (void *) hfc_dbusy_timer;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c
--- v2.3.9/linux/drivers/isdn/hisax/hfc_2bs0.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/hfc_2bs0.c	Tue Jul  6 19:05:48 1999
@@ -555,8 +555,8 @@
 	return (0);
 }
 
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init 
+init_send(struct BCState *bcs)
 {
 	int i;
 
@@ -569,8 +569,8 @@
 		bcs->hw.hfc.send[i] = 0x1fff;
 }
 
-__initfunc(void
-inithfc(struct IsdnCardState *cs))
+void __init 
+inithfc(struct IsdnCardState *cs)
 {
 	init_send(&cs->bcs[0]);
 	init_send(&cs->bcs[1]);
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c
--- v2.3.9/linux/drivers/isdn/hisax/ix1_micro.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/ix1_micro.c	Tue Jul  6 19:05:48 1999
@@ -289,8 +289,8 @@
 }
 
 
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init 
+setup_ix1micro(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c
--- v2.3.9/linux/drivers/isdn/hisax/mic.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/mic.c	Tue Jul  6 19:05:48 1999
@@ -231,8 +231,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init 
+setup_mic(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- v2.3.9/linux/drivers/isdn/hisax/netjet.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/netjet.c	Tue Jul  6 19:05:48 1999
@@ -858,8 +858,8 @@
 }
 
  
-__initfunc(void
-inittiger(struct IsdnCardState *cs))
+void __init 
+inittiger(struct IsdnCardState *cs)
 {
 	if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int),
 		GFP_KERNEL | GFP_DMA))) {
@@ -1050,8 +1050,8 @@
 
 static 	struct pci_dev *dev_netjet __initdata = NULL;
 
-__initfunc(int
-setup_netjet(struct IsdnCard *card))
+int __init 
+setup_netjet(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- v2.3.9/linux/drivers/isdn/hisax/niccy.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/niccy.c	Tue Jul  6 19:05:48 1999
@@ -263,8 +263,8 @@
 
 static 	struct pci_dev *niccy_dev __initdata = NULL;
 
-__initfunc(int
-setup_niccy(struct IsdnCard *card))
+int __init 
+setup_niccy(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- v2.3.9/linux/drivers/isdn/hisax/sedlbauer.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/sedlbauer.c	Tue Jul  6 19:05:48 1999
@@ -533,8 +533,8 @@
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_sedlbauer(struct IsdnCard *card))
+int __init 
+setup_sedlbauer(struct IsdnCard *card)
 {
 	int bytecnt, ver, val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c
--- v2.3.9/linux/drivers/isdn/hisax/sportster.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/sportster.c	Tue Jul  6 19:05:48 1999
@@ -204,8 +204,8 @@
 	return(0);
 }
 
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+int __init 
+get_io_range(struct IsdnCardState *cs)
 {
 	int i, j, adr;
 	
@@ -230,8 +230,8 @@
 	}
 }
 
-__initfunc(int
-setup_sportster(struct IsdnCard *card))
+int __init 
+setup_sportster(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c
--- v2.3.9/linux/drivers/isdn/hisax/teleint.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/teleint.c	Tue Jul  6 19:05:49 1999
@@ -289,8 +289,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init 
+setup_TeleInt(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- v2.3.9/linux/drivers/isdn/hisax/teles0.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/teles0.c	Tue Jul  6 19:05:49 1999
@@ -302,8 +302,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init 
+setup_teles0(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- v2.3.9/linux/drivers/isdn/hisax/teles3.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/teles3.c	Tue Jul  6 19:05:49 1999
@@ -321,8 +321,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int __init 
+setup_teles3(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teles3c.c linux/drivers/isdn/hisax/teles3c.c
--- v2.3.9/linux/drivers/isdn/hisax/teles3c.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/teles3c.c	Tue Jul  6 19:05:49 1999
@@ -140,8 +140,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_t163c(struct IsdnCard *card))
+int __init 
+setup_t163c(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c
--- v2.3.9/linux/drivers/isdn/isdn_bsdcomp.c	Sun May 23 10:03:42 1999
+++ linux/drivers/isdn/isdn_bsdcomp.c	Mon Jul  5 20:35:18 1999
@@ -64,7 +64,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 
diff -u --recursive --new-file v2.3.9/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.9/linux/drivers/macintosh/macserial.c	Mon Jun  7 12:12:32 1999
+++ linux/drivers/macintosh/macserial.c	Thu Jul  1 15:09:01 1999
@@ -1558,7 +1558,6 @@
 		char_time = MIN(char_time, timeout);
 	while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/Config.in linux/drivers/misc/Config.in
--- v2.3.9/linux/drivers/misc/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/Config.in	Thu Jul  1 14:22:57 1999
@@ -0,0 +1,37 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+# Parport configuration.
+#
+
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+    bool '   Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
+  fi
+  if [ "$CONFIG_ARM" = "y" ]; then
+    dep_tristate '   Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+  fi
+  if [ "$CONFIG_AMIGA" = "y" ]; then
+    dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+    if [ "$CONFIG_ZORRO" != "n" ]; then
+      dep_tristate '   Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+    fi
+  else
+    define_bool CONFIG_PARPORT_AMIGA n
+    define_bool CONFIG_PARPORT_MFC3 n
+  fi
+  if [ "$CONFIG_ATARI" = "y" ]; then
+    dep_tristate '   Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+  else
+    define_bool CONFIG_PARPORT_ATARI n
+  fi
+
+  # If exactly one hardware type is selected then parport will optimise away
+  # support for loading any others.  Defeat this if the user is keen.
+  bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
+
+  bool '   IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+fi
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/Makefile linux/drivers/misc/Makefile
--- v2.3.9/linux/drivers/misc/Makefile	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/Makefile	Thu Jul  1 14:22:57 1999
@@ -23,7 +23,13 @@
 MIX_OBJS :=
 
 ifeq ($(CONFIG_PARPORT),y)
-  L_OBJS += parport_share.o parport_ieee1284.o parport_procfs.o
+  L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \
+            parport_procfs.o
+
+  ifeq ($(CONFIG_PARPORT_1284),y)
+    L_OBJS += parport_daisy.o parport_probe.o
+  endif
+
   ifeq ($(CONFIG_PARPORT_PC),y)
     LX_OBJS += parport_pc.o
   else
@@ -62,7 +68,10 @@
   LX_OBJS += parport_init.o
 else
   ifeq ($(CONFIG_PARPORT),m)
-    MI_OBJS += parport_share.o parport_ieee1284.o
+    MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o
+    ifeq ($(CONFIG_PARPORT_1284),y)
+      MI_OBJS += parport_daisy.o parport_probe.o
+    endif
     ifneq ($(CONFIG_PROC_FS),n) 
       MI_OBJS += parport_procfs.o
     endif
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.3.9/linux/drivers/misc/parport_arc.c	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/parport_arc.c	Thu Jul  1 14:22:57 1999
@@ -98,41 +98,36 @@
 	arc_read_control,
 	arc_frob_control,
 
-	NULL, /* write_econtrol */
-	NULL, /* read_econtrol */
-	NULL, /* frob_econtrol */
-
-	arc_write_status,
 	arc_read_status,
 
-	NULL, /* write_fifo */
-	NULL, /* read_fifo */
-	
-	NULL, /* change_mode */
-	
-	NULL, /* epp_write_data */
-	NULL, /* epp_read_data */
-	NULL, /* epp_write_addr */
-	NULL, /* epp_read_addr */
-	NULL, /* epp_check_timeout */
+	arc_enable_irq,
+	arc_disable_irq,
 
-	NULL, /* epp_write_block */
-	NULL, /* epp_read_block */
+	arc_data_forward,
+	arc_data_reverse,
+
+	arc_interrupt,
 
-	NULL, /* ecp_write_block */
-	NULL, /* epp_write_block */
-	
 	arc_init_state,
 	arc_save_state,
 	arc_restore_state,
 
-	arc_enable_irq,
-	arc_disable_irq,
-	arc_interrupt,
-
 	arc_inc_use_count,
 	arc_dec_use_count,
-	arc_fill_inode
+	arc_fill_inode,
+
+	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,
 };
 
 /* --- Initialisation code -------------------------------- */
@@ -142,11 +137,11 @@
 	/* Archimedes hardware provides only one port, at a fixed address */
 	struct parport *p;
 
-	if (check_region(PORT_BASE, 4))
+	if (check_region(PORT_BASE, 1))
 		return 0;
-	
-	p = parport_register_port(base, IRQ_PRINTERACK, 
-				  PARPORT_DMA_NONE, &parport_arc_ops);
+
+	p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
+				   PARPORT_DMA_NONE, &parport_arc_ops);
 
 	if (!p)
 		return 0;
@@ -157,9 +152,6 @@
 	printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
 	       p->irq);
 	parport_proc_register(p);
-
-	if (parport_probe_hook)
-		(*parport_probe_hook)(p);
 
 	/* Tell the high-level drivers about the port. */
 	parport_announce_port (p);
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_atari.c linux/drivers/misc/parport_atari.c
--- v2.3.9/linux/drivers/misc/parport_atari.c	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/parport_atari.c	Thu Jul  1 14:22:57 1999
@@ -221,9 +221,6 @@
 		printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
 		parport_proc_register(p);
 
-		if (parport_probe_hook)
-			(*parport_probe_hook)(p);
-
 		parport_announce_port (p);
 
 		return 1;
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c
--- v2.3.9/linux/drivers/misc/parport_ax.c	Wed Jun  9 14:44:25 1999
+++ linux/drivers/misc/parport_ax.c	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/* $Id: parport_ax.c,v 1.19 1999/06/09 08:24:40 davem Exp $
+/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
  * Parallel-port routines for Sun Ultra/AX architecture
  * 
  * Author: Eddie C. Dost <ecd@skynet.be>
@@ -164,6 +164,7 @@
 void
 parport_ax_change_mode(struct parport *p, int m)
 {
+	/* FIXME */
 	parport_ax_frob_econtrol(p, 0xe0, m << 5);
 }
 
@@ -201,58 +202,40 @@
 	writel(dcsr, (unsigned long)&dma->dcsr);
 }
 
-int
-parport_ax_claim_resources(struct parport *p)
-{
-}
-
 void
-parport_ax_init_state(struct parport_state *s)
+parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
 {
-	s->u.pc.ctr = 0xc;
-	s->u.pc.ecr = 0x0;
+	struct linux_ebus_dma *dma = dev->port->private_data;
+
+	s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+	s->u.ax.ecr = 0x0;
+
+	if (dev->irq_func)
+		s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+				| EBUS_DCSR_INT_EN);
+	else
+		s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+				& ~EBUS_DCSR_INT_EN);
 }
 
 void
 parport_ax_save_state(struct parport *p, struct parport_state *s)
 {
-	s->u.pc.ctr = parport_ax_read_control(p);
-	s->u.pc.ecr = parport_ax_read_econtrol(p);
+	struct linux_ebus_dma *dma = p->private_data;
+
+	s->u.ax.ctr = parport_ax_read_control(p);
+	s->u.ax.ecr = parport_ax_read_econtrol(p);
+	s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
 }
 
 void
 parport_ax_restore_state(struct parport *p, struct parport_state *s)
 {
-	parport_ax_write_control(p, s->u.pc.ctr);
-	parport_ax_write_econtrol(p, s->u.pc.ecr);
-}
-
-size_t
-parport_ax_epp_read_block(struct parport *p, void *buf, size_t length)
-{
-	return 0; /* FIXME */
-}
-
-size_t
-parport_ax_epp_write_block(struct parport *p, void *buf, size_t length)
-{
-	return 0; /* FIXME */
-}
-
-int
-parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length,
-			  void (*fn)(struct parport *, void *, size_t),
-			  void *handle)
-{
-	return 0; /* FIXME */
-}
+	struct linux_ebus_dma *dma = p->private_data;
 
-int
-parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length,
-			   void (*fn)(struct parport *, void *, size_t),
-			   void *handle)
-{
-	return 0; /* FIXME */
+	parport_ax_write_control(p, s->u.ax.ctr);
+	parport_ax_write_econtrol(p, s->u.ax.ecr);
+	writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
 }
 
 void
@@ -290,41 +273,36 @@
 	parport_ax_read_control,
 	parport_ax_frob_control,
 
-	parport_ax_write_econtrol,
-	parport_ax_read_econtrol,
-	parport_ax_frob_econtrol,
-
-	parport_ax_write_status,
 	parport_ax_read_status,
 
-	parport_ax_write_fifo,
-	parport_ax_read_fifo,
-	
-	parport_ax_change_mode,
-	
-	parport_ax_write_epp,
-	parport_ax_read_epp,
-	parport_ax_write_epp_addr,
-	parport_ax_read_epp_addr,
-	parport_ax_check_epp_timeout,
+	parport_ax_enable_irq,
+	parport_ax_disable_irq,
 
-	parport_ax_epp_write_block,
-	parport_ax_epp_read_block,
+	parport_ax_data_forward,
+	parport_ax_data_reverse,
+
+	parport_ax_interrupt,
 
-	parport_ax_ecp_write_block,
-	parport_ax_ecp_read_block,
-	
 	parport_ax_init_state,
 	parport_ax_save_state,
 	parport_ax_restore_state,
 
-	parport_ax_enable_irq,
-	parport_ax_disable_irq,
-	parport_ax_interrupt,
-
 	parport_ax_inc_use_count,
 	parport_ax_dec_use_count,
-	parport_ax_fill_inode
+	parport_ax_fill_inode,
+
+	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,
 };
 
 
@@ -539,20 +517,6 @@
 	if (p->dma == PARPORT_DMA_AUTO)
 		p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
 
-	if (p->irq != PARPORT_IRQ_NONE) {
-		int err;
-		if ((err = request_irq(p->irq, parport_ax_interrupt,
-				       0, p->name, p)) != 0)
-			return err;
-		else
-			parport_ax_enable_irq(p);
-	}
-	request_region(p->base, p->size, p->name);
-	if (p->modes & PARPORT_MODE_PCECR)
-		request_region(p->base+0x400, 3, p->name);
-	request_region((unsigned long)p->private_data,
-		       sizeof(struct linux_ebus_dma), p->name);
-
 	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
 	if (p->irq != PARPORT_IRQ_NONE)
 		printk(", irq %s", __irq_itoa(p->irq));
@@ -569,12 +533,21 @@
 	printk("]\n");
 	parport_proc_register(p);
 
+	if (p->irq != PARPORT_IRQ_NONE)
+		if ((err = request_irq(p->irq, parport_ax_interrupt,
+				       0, p->name, p)) != 0)
+			return 0;		/* @@@ FIXME */
+
+	request_region(p->base, p->size, p->name);
+	if (p->modes & PARPORT_MODE_PCECR)
+		request_region(p->base+0x400, 3, p->name);
+	request_region((unsigned long)p->private_data,
+		       sizeof(struct linux_ebus_dma), p->name);
+
 	p->ops->write_control(p, 0x0c);
 	p->ops->write_data(p, 0);
 
-	if (parport_probe_hook)
-		(*parport_probe_hook)(p);
-
+	/* Tell the high-level drivers about the port. */
 	parport_announce_port (p);
 
 	return 1;
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_daisy.c linux/drivers/misc/parport_daisy.c
--- v2.3.9/linux/drivers/misc/parport_daisy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_daisy.c	Sat Jul  3 10:45:04 1999
@@ -0,0 +1,473 @@
+/*
+ * IEEE 1284.3 Parallel port daisy chain and multiplexor code
+ * 
+ * Copyright (C) 1999  Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * 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.
+ *
+ * ??-12-1998: Initial implementation.
+ * 31-01-1999: Make port-cloning transparent.
+ * 13-02-1999: Move DeviceID technique from parport_probe.
+ * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
+ *
+ */
+
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+static struct daisydev {
+	struct daisydev *next;
+	struct parport *port;
+	int daisy;
+	int devnum;
+} *topology = NULL;
+
+static int numdevs = 0;
+
+/* Forward-declaration of lower-level functions. */
+static int mux_present (struct parport *port);
+static int num_mux_ports (struct parport *port);
+static int select_port (struct parport *port);
+static int assign_addrs (struct parport *port);
+
+/* Add a device to the discovered topology. */
+static void add_dev (int devnum, struct parport *port, int daisy)
+{
+	struct daisydev *newdev;
+	newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
+	if (newdev) {
+		newdev->port = port;
+		newdev->daisy = daisy;
+		newdev->devnum = devnum;
+		newdev->next = topology;
+		if (!topology || topology->devnum >= devnum)
+			topology = newdev;
+		else {
+			struct daisydev *prev = topology;
+			while (prev->next && prev->next->devnum < devnum)
+				prev = prev->next;
+			newdev->next = prev->next;
+			prev->next = newdev;
+		}
+	}
+}
+
+/* Clone a parport (actually, make an alias). */
+static struct parport *clone_parport (struct parport *real, int muxport)
+{
+	struct parport *extra = parport_register_port (real->base,
+						       real->irq,
+						       real->dma,
+						       real->ops);
+	if (extra) {
+		extra->portnum = real->portnum;
+		extra->physport = real;
+		extra->muxport = muxport;
+	}
+
+	return extra;
+}
+
+/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
+int parport_daisy_init (struct parport *port)
+{
+	char *deviceid;
+	static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
+	int num_ports;
+	int i;
+
+	/* Because this is called before any other devices exist,
+	 * we don't have to claim exclusive access.  */
+
+	/* If mux present on normal port, need to create new
+	 * parports for each extra port. */
+	if (port->muxport < 0 && mux_present (port) &&
+	    /* don't be fooled: a mux must have 2 or 4 ports. */
+	    ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
+		/* Leave original as port zero. */
+		port->muxport = 0;
+		printk (KERN_INFO
+			"%s: 1st (default) port of %d-way multiplexor\n",
+			port->name, num_ports);
+		for (i = 1; i < num_ports; i++) {
+			/* Clone the port. */
+			struct parport *extra = clone_parport (port, i);
+			if (!extra) {
+				if (signal_pending (current))
+					break;
+
+				schedule ();
+				continue;
+			}
+
+			printk (KERN_INFO
+				"%s: %d%s port of %d-way multiplexor on %s\n",
+				extra->name, i + 1, th[i + 1], num_ports,
+				port->name);
+
+			/* Analyse that port too.  We won't recurse
+			   forever because of the 'port->muxport < 0'
+			   test above. */
+			parport_announce_port (extra);
+		}
+	}
+
+	if (port->muxport >= 0)
+		select_port (port);
+
+	parport_daisy_deselect_all (port);
+	assign_addrs (port);
+
+	/* Count the potential legacy device at the end. */
+	add_dev (numdevs++, port, -1);
+
+	/* Find out the legacy device's IEEE 1284 device ID. */
+	deviceid = kmalloc (1000, GFP_KERNEL);
+	if (deviceid) {
+		parport_device_id (numdevs - 1, deviceid, 1000);
+		kfree (deviceid);
+	}
+
+	return 0;
+}
+
+/* Forget about devices on a physical port. */
+void parport_daisy_fini (struct parport *port)
+{
+	struct daisydev *dev, *prev = topology;
+	while (prev && prev->port == port)
+		prev = topology = topology->next;
+
+	while (prev) {
+		dev = prev->next;
+		if (dev && dev->port == port)
+			prev->next = dev->next;
+
+		prev = prev->next;
+	}
+
+	/* Gaps in the numbering could be handled better.  How should
+           someone enumerate through all IEEE1284.3 devices in the
+           topology?. */
+	if (!topology) numdevs = 0;
+	return; }
+
+/* Find a device by canonical device number. */
+struct pardevice *parport_open (int devnum, const char *name,
+				int (*pf) (void *), void (*kf) (void *),
+				void (*irqf) (int, void *, struct pt_regs *),
+				int flags, void *handle)
+{
+	struct parport *port = parport_enumerate ();
+	struct pardevice *dev;
+	int portnum;
+	int muxnum;
+	int daisynum;
+
+	if (parport_device_coords (devnum,  &portnum, &muxnum, &daisynum))
+		return NULL;
+
+	while (port && ((port->portnum != portnum) ||
+			(port->muxport != muxnum)))
+		port = port->next;
+
+	if (!port)
+		/* No corresponding parport. */
+		return NULL;
+
+	dev = parport_register_device (port, name, pf, kf,
+				       irqf, flags, handle);
+	if (dev)
+		dev->daisy = daisynum;
+
+	/* Check that there really is a device to select. */
+	if (daisynum >= 0) {
+		int selected;
+		parport_claim_or_block (dev);
+		selected = port->daisy;
+		parport_release (dev);
+
+		if (selected != port->daisy) {
+			/* No corresponding device. */
+			parport_unregister_device (dev);
+			return NULL;
+		}
+	}
+
+	return dev;
+}
+
+/* The converse of parport_open. */
+void parport_close (struct pardevice *dev)
+{
+	parport_unregister_device (dev);
+}
+
+/* Convert device coordinates into a canonical device number. */
+int parport_device_num (int parport, int mux, int daisy)
+{
+	struct daisydev *dev = topology;
+
+	while (dev && dev->port->portnum != parport &&
+	       dev->port->muxport != mux && dev->daisy != daisy)
+		dev = dev->next;
+
+	if (!dev)
+		return -ENXIO;
+
+	return dev->devnum;
+}
+
+/* Convert a canonical device number into device coordinates. */
+int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
+{
+	struct daisydev *dev = topology;
+
+	while (dev && dev->devnum != devnum)
+		dev = dev->next;
+
+	if (!dev)
+		return -ENXIO;
+
+	if (parport) *parport = dev->port->portnum;
+	if (mux) *mux = dev->port->muxport;
+	if (daisy) *daisy = dev->daisy;
+	return 0;
+}
+
+/* Send a daisy-chain-style CPP command packet. */
+static int cpp_daisy (struct parport *port, int cmd)
+{
+	unsigned char s;
+
+	parport_write_data (port, 0xaa); udelay (2);
+	parport_write_data (port, 0x55); udelay (2);
+	parport_write_data (port, 0x00); udelay (2);
+	parport_write_data (port, 0xff); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_BUSY
+		  | PARPORT_STATUS_PAPEROUT
+		  | PARPORT_STATUS_SELECT
+		  | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x87); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x78); udelay (2);
+	parport_write_data (port, cmd); udelay (2);
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE,
+			      PARPORT_CONTROL_STROBE);
+	udelay (1);
+	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+	udelay (1);
+	s = parport_read_status (port);
+	parport_write_data (port, 0xff); udelay (2);
+
+	return s;
+}
+
+/* Send a mux-style CPP command packet. */
+static int cpp_mux (struct parport *port, int cmd)
+{
+	unsigned char s;
+	int rc;
+
+	parport_write_data (port, 0xaa); udelay (2);
+	parport_write_data (port, 0x55); udelay (2);
+	parport_write_data (port, 0xf0); udelay (2);
+	parport_write_data (port, 0x0f); udelay (2);
+	parport_write_data (port, 0x52); udelay (2);
+	parport_write_data (port, 0xad); udelay (2);
+	parport_write_data (port, cmd); udelay (2);
+
+	s = parport_read_status (port);
+	if (!(s & PARPORT_STATUS_ACK)) {
+		DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+			 port->name, cmd, s);
+		return -EIO;
+	}
+
+	rc = (((s & PARPORT_STATUS_SELECT   ? 1 : 0) << 0) |
+	      ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
+	      ((s & PARPORT_STATUS_BUSY     ? 0 : 1) << 2) |
+	      ((s & PARPORT_STATUS_ERROR    ? 0 : 1) << 3));
+
+	return rc;
+}
+
+void parport_daisy_deselect_all (struct parport *port)
+{
+	cpp_daisy (port, 0x30);
+}
+
+int parport_daisy_select (struct parport *port, int daisy, int mode)
+{
+	/* mode is currently ignored. FIXME? */
+	return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
+}
+
+static int mux_present (struct parport *port)
+{
+	return cpp_mux (port, 0x51) == 3;
+}
+
+static int num_mux_ports (struct parport *port)
+{
+	return cpp_mux (port, 0x58);
+}
+
+static int select_port (struct parport *port)
+{
+	int muxport = port->muxport;
+	return cpp_mux (port, 0x60 + muxport) == muxport;
+}
+
+static int assign_addrs (struct parport *port)
+{
+	unsigned char s, last_dev;
+	unsigned char daisy;
+	int thisdev = numdevs;
+	char *deviceid;
+
+	parport_write_data (port, 0xaa); udelay (2);
+	parport_write_data (port, 0x55); udelay (2);
+	parport_write_data (port, 0x00); udelay (2);
+	parport_write_data (port, 0xff); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_BUSY
+		  | PARPORT_STATUS_PAPEROUT
+		  | PARPORT_STATUS_SELECT
+		  | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x87); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x78); udelay (2);
+	last_dev = 0; /* We've just been speaking to a device, so we
+			 know there must be at least _one_ out there. */
+
+	for (daisy = 0; daisy < 4; daisy++) {
+		parport_write_data (port, daisy);
+		udelay (2);
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+		udelay (1);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+		udelay (1);
+
+		if (last_dev)
+			/* No more devices. */
+			break;
+
+		last_dev = !(parport_read_status (port)
+			     & PARPORT_STATUS_BUSY);
+
+		add_dev (numdevs++, port, daisy);
+	}
+
+	parport_write_data (port, 0xff); udelay (2);
+	DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+		numdevs - thisdev);
+
+	/* Ask the new devices to introduce themselves. */
+	deviceid = kmalloc (1000, GFP_KERNEL);
+	if (!deviceid) return 0;
+
+	for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
+		parport_device_id (thisdev, deviceid, 1000);
+
+	kfree (deviceid);
+	return 0;
+}
+
+/* Find a device with a particular manufacturer and model string,
+   starting from a given device number.  Like the PCI equivalent,
+   'from' itself is skipped. */
+int parport_find_device (const char *mfg, const char *mdl, int from)
+{
+	struct daisydev *d = topology; /* sorted by devnum */
+
+	/* Find where to start. */
+	while (d && d->devnum <= from)
+		d = d->next;
+
+	/* Search. */
+	while (d) {
+		struct parport_device_info *info;
+		info = &d->port->probe_info[1 + d->daisy];
+		if ((!mfg || !strcmp (mfg, info->mfr)) &&
+		    (!mdl || !strcmp (mdl, info->model)))
+			break;
+
+		d = d->next;
+	}
+
+	if (d)
+		return d->devnum;
+
+	return -1;
+}
+
+/* Find a device in a particular class.  Like the PCI equivalent,
+   'from' itself is skipped. */
+int parport_find_class (parport_device_class cls, int from)
+{
+	struct daisydev *d = topology; /* sorted by devnum */
+
+	/* Find where to start. */
+	while (d && d->devnum <= from)
+		d = d->next;
+
+	/* Search. */
+	while (d && d->port->probe_info[1 + d->daisy].class != cls)
+		d = d->next;
+
+	if (d)
+		return d->devnum;
+
+	return -1;
+}
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.3.9/linux/drivers/misc/parport_ieee1284.c	Mon May 10 10:26:31 1999
+++ linux/drivers/misc/parport_ieee1284.c	Wed Jul  7 12:55:47 1999
@@ -4,12 +4,73 @@
  * Authors: Phil Blundell <Philip.Blundell@pobox.com>
  *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
  *	    Jose Renau <renau@acm.org>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
+ *
+ * This file is responsible for IEEE 1284 negotiation, and for handing
+ * read/write requests to low-level drivers.
  */
 
+#include <linux/config.h>
 #include <linux/tasks.h>
 #include <linux/parport.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#undef DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/* Make parport_wait_peripheral wake up.
+ * It will be useful to call this from an interrupt handler. */
+void parport_ieee1284_wakeup (struct parport *port)
+{
+	up (&port->physport->ieee1284.irq);
+}
+
+static struct parport *port_from_cookie[PARPORT_MAX];
+static void timeout_waiting_on_port (unsigned long cookie)
+{
+	parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
+}
+
+/* Wait for a parport_ieee1284_wakeup.
+ * 0:      success
+ * <0:     error (exit as soon as possible)
+ * >0:     timed out
+ */
+int parport_wait_event (struct parport *port, signed long timeout)
+{
+	int ret;
+	struct timer_list timer;
+
+	if (!port->physport->cad->timeout)
+		/* Zero timeout is special, and we can't down() the
+		   semaphore. */
+		return 1;
+
+	init_timer (&timer);
+	timer.expires = jiffies + timeout;
+	timer.function = timeout_waiting_on_port;
+	port_from_cookie[port->number % PARPORT_MAX] = port;
+	timer.data = port->number;
+
+	add_timer (&timer);
+	ret = down_interruptible (&port->physport->ieee1284.irq);
+	if (!del_timer (&timer) && !ret)
+		/* Timed out. */
+		ret = 1;
+
+	return ret;
+}
 
 /* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
  * 25 for this. After this time we can create a timeout because the
@@ -19,53 +80,446 @@
  * are able to eat the time up to 40ms.
  */ 
 
-int parport_wait_peripheral(struct parport *port, unsigned char mask, 
-	unsigned char result)
+int parport_wait_peripheral(struct parport *port,
+			    unsigned char mask, 
+			    unsigned char result)
 {
 	int counter;
-	unsigned char status; 
-	
-	for (counter = 0; counter < 20; counter++) {
-		status = parport_read_status(port);
+	long deadline;
+	unsigned char status;
+
+	counter = port->physport->spintime; /* usecs of fast polling */
+	if (!port->physport->cad->timeout)
+		/* A zero timeout is "special": busy wait for the
+		   entire 35ms. */
+		counter = 35000;
+
+	/* Fast polling.
+	 *
+	 * This should be adjustable.
+	 * How about making a note (in the device structure) of how long
+	 * it takes, so we know for next time?
+	 */
+	for (counter /= 5; counter > 0; counter--) {
+		status = parport_read_status (port);
 		if ((status & mask) == result)
 			return 0;
-		udelay(25);
+		if (signal_pending (current))
+			return -EINTR;
 		if (current->need_resched)
-			schedule();
+			break;
+		udelay(5);
 	}
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ/25);				/* wait for 40ms */
-	status = parport_read_status(port);
-	return ((status & mask) == result)?0:1;
+
+	if (!port->physport->cad->timeout)
+		/* We may be in an interrupt handler, so we can't poll
+		 * slowly anyway. */
+		return 1;
+
+	/* 40ms of slow polling. */
+	deadline = jiffies + (HZ + 24) / 25;
+	while (time_before (jiffies, deadline)) {
+		int ret;
+
+		if (signal_pending (current))
+			return -EINTR;
+
+		/* Wait for 10ms (or until an interrupt occurs if
+		 * the handler is set) */
+		if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
+			return ret;
+
+		status = parport_read_status (port);
+		if ((status & mask) == result)
+			return 0;
+
+		if (!ret) {
+			/* parport_wait_event didn't time out, but the
+			 * peripheral wasn't actually ready either.
+			 * Wait for another 10ms. */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout ((HZ+ 99) / 100);
+		}
+	}
+
+	return 1;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Terminate a negotiated mode. */
+static void parport_ieee1284_terminate (struct parport *port)
+{
+	port = port->physport;
+
+	port->ieee1284.phase = IEEE1284_PH_TERMINATE;
+
+	/* EPP terminates differently. */
+	switch (port->ieee1284.mode) {
+	case IEEE1284_MODE_EPP:
+	case IEEE1284_MODE_EPPSL:
+	case IEEE1284_MODE_EPPSWE:
+		/* Terminate from EPP mode. */
+
+		/* Event 68: Set nInit low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
+		udelay (50);
+
+		/* Event 69: Set nInit high, nSelectIn low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
+		break;
+		
+	default:
+		/* Terminate from all other modes. */
+
+		/* Event 22: Set nSelectIn low, nAutoFd high */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_SELECT
+				      | PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_SELECT);
+
+		/* Event 24: nAck goes low */
+		parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+
+		/* Event 25: Set nAutoFd low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 27: nAck goes high */
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_ACK, 
+					 PARPORT_STATUS_ACK);
+
+		/* Event 29: Set nAutoFd high */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+	}
+
+	port->ieee1284.mode = IEEE1284_MODE_COMPAT;
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
+		 port->name);
 }		
+#endif /* IEEE1284 support */
 
-/* Test if the peripheral is IEEE 1284 compliant.
+/* Negotiate an IEEE 1284 mode.
  * return values are:
- *   0 - handshake failed; peripheral is not compliant (or none present)
- *   1 - handshake OK; IEEE1284 peripheral present but no data available
- *   2 - handshake OK; IEEE1284 peripheral and data available
+ *   0 - handshake OK; IEEE1284 peripheral and mode available
+ *  -1 - handshake failed; peripheral is not compliant (or none present)
+ *   1 - handshake OK; IEEE1284 peripheral present but mode not available
  */
-int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) 
+int parport_negotiate (struct parport *port, int mode)
 {
-	/* make sure it's a valid state, set nStrobe & nAutoFeed high */
-	parport_frob_control (port, (1|2), 0);
-	udelay(1);
-	parport_write_data(port, mode);
-	udelay(400);
-	/* nSelectIn high, nAutoFd low */
-	parport_frob_control(port, (2|8), 2);
-	if (parport_wait_peripheral(port, 0x78, 0x38)) {
-		parport_frob_control(port, (2|8), 8);
+#ifndef CONFIG_PARPORT_1284
+	if (mode == IEEE1284_MODE_COMPAT)
+		return 0;
+	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+	return -1;
+#else
+	int m = mode;
+	unsigned char xflag;
+
+	port = port->physport;
+
+	/* Is there anything to do? */
+	if (port->ieee1284.mode == mode)
+		return 0;
+
+	/* Go to compability forward idle mode */
+	if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
+		parport_ieee1284_terminate (port);
+
+	if (mode == IEEE1284_MODE_COMPAT)
+		/* Compatibility mode: no negotiation. */
 		return 0; 
+
+	switch (mode) {
+	case IEEE1284_MODE_ECPSWE:
+		m = IEEE1284_MODE_ECP;
+		break;
+	case IEEE1284_MODE_EPPSL:
+	case IEEE1284_MODE_EPPSWE:
+		m = IEEE1284_MODE_EPP;
+		break;
+	case IEEE1284_MODE_BECP:
+		return -ENOSYS; /* FIXME (implement BECP) */
 	}
-	/* nStrobe low */
-	parport_frob_control (port, 1, 1);
-	udelay(1);				     /* Strobe wait */
-	/* nStrobe high, nAutoFeed low, last step before transferring 
-	 *  reverse data */
-	parport_frob_control (port, (1|2), 0);
+
+	port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
+
+	/* Start off with nStrobe and nAutoFd high, and nSelectIn low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_AUTOFD
+			      | PARPORT_CONTROL_SELECT,
+			      PARPORT_CONTROL_SELECT);
 	udelay(1);
-	/* Data available? */
-	parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
-	return (parport_read_status(port) & PARPORT_STATUS_ERROR)?1:2;
+
+	/* Event 0: Set data */
+	parport_write_data (port, m);
+	udelay (400); /* Shouldn't need to wait this long. */
+
+	/* Event 1: Set nSelectIn high, nAutoFd low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_SELECT
+			      | PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_AUTOFD);
+
+	/* Event 2: PError, Select, nFault go high, nAck goes low */
+	if (parport_wait_peripheral (port,
+				     PARPORT_STATUS_ERROR
+				     | PARPORT_STATUS_SELECT
+				     | PARPORT_STATUS_PAPEROUT
+				     | PARPORT_STATUS_ACK,
+				     PARPORT_STATUS_ERROR
+				     | PARPORT_STATUS_SELECT
+				     | PARPORT_STATUS_PAPEROUT)) {
+		/* Timeout */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_SELECT
+				      | PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_SELECT);
+		DPRINTK (KERN_DEBUG
+			 "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
+			 port->name, parport_read_status (port));
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+		return -1; /* Not IEEE1284 compliant */
+	}
+
+	/* Event 3: Set nStrobe low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE,
+			      PARPORT_CONTROL_STROBE);
+
+	/* Event 4: Set nStrobe and nAutoFd high */
+	udelay (5);
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_AUTOFD,
+			      0);
+
+	/* Event 6: nAck goes high */
+	if (parport_wait_peripheral (port,
+				     PARPORT_STATUS_ACK
+				     | PARPORT_STATUS_PAPEROUT,
+				     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);
+		DPRINTK (KERN_DEBUG
+			 "%s: Mode 0x%02x not supported? (0x%02x)\n",
+			 port->name, mode, port->ops->read_status (port));
+		parport_ieee1284_terminate (port);
+		return 1;
+	}
+
+	xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
+
+	/* xflag should be high for all modes other than nibble (0). */
+	if (mode && !xflag) {
+		/* Mode not supported. */
+		DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
+			 port->name, mode);
+		parport_ieee1284_terminate (port);
+		return 1;
+	}
+
+	/* Mode is supported */
+	DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
+	port->ieee1284.mode = mode;
+
+	/* But ECP is special */
+	if (mode & IEEE1284_MODE_ECP) {
+		port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
+
+		/* Event 30: Set nAutoFd low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 31: PError goes high. */
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_PAPEROUT,
+					 PARPORT_STATUS_PAPEROUT);
+		/* (Should check that this works..) */
+
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+			 port->name);
+	} else switch (mode) {
+	case IEEE1284_MODE_NIBBLE:
+	case IEEE1284_MODE_BYTE:
+		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+		break;
+	default:
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	}
+
+
+	return 0;
+#endif /* IEEE1284 support */
+}
+
+/* Acknowledge that the peripheral has data available.
+ * Events 18-20, in order to get from Reverse Idle phase
+ * to Host Busy Data Available.
+ * This will most likely be called from an interrupt.
+ * Returns zero if data was available.
+ */
+#ifdef CONFIG_PARPORT_1284
+static int parport_ieee1284_ack_data_avail (struct parport *port)
+{
+	if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+		/* Event 18 didn't happen. */
+		return -1;
+
+	/* Event 20: nAutoFd goes high. */
+	port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+	port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+	return 0;
+}
+#endif /* IEEE1284 support */
+
+/* Handle an interrupt. */
+void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
+{
+	struct parport *port = handle;
+	parport_ieee1284_wakeup (port);
+
+#ifdef CONFIG_PARPORT_1284
+	if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
+		/* An interrupt in this phase means that data
+		 * is now available. */
+		DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
+		parport_ieee1284_ack_data_avail (port);
+	}
+#endif /* IEEE1284 support */
+}
+
+/* Write a block of data. */
+ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+	return port->ops->compat_write_data (port, buffer, len, 0);
+#else
+	ssize_t retval;
+	int mode = port->ieee1284.mode;
+	size_t (*fn) (struct parport *, const void *, size_t, int);
+
+	/* Ignore the device-ID-request bit. */
+	mode &= ~IEEE1284_DEVICEID;
+
+	/* Use the mode we're in. */
+	switch (mode) {
+	case IEEE1284_MODE_NIBBLE:
+		parport_negotiate (port, IEEE1284_MODE_COMPAT);
+	case IEEE1284_MODE_COMPAT:
+		DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
+			 port->name);
+		fn = port->ops->compat_write_data;
+		break;
+
+	case IEEE1284_MODE_EPP:
+		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+		fn = port->ops->epp_write_data;
+		break;
+
+	case IEEE1284_MODE_ECP:
+	case IEEE1284_MODE_ECPRLE:
+		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+		fn = port->ops->ecp_write_data;
+		break;
+
+	case IEEE1284_MODE_ECPSWE:
+		DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+			 port->name);
+		/* The caller has specified that it must be emulated,
+		 * even if we have ECP hardware! */
+		fn = parport_ieee1284_ecp_write_data;
+		break;
+
+	default:
+		DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+			port->ieee1284.mode);
+		return -ENOSYS;
+	}
+
+	retval = (*fn) (port, buffer, len, 0);
+	DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
+		 len);
+	return retval;
+#endif /* IEEE1284 support */
+}
+
+/* Read a block of data. */
+ssize_t parport_read (struct parport *port, void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+	return -ENODEV;
+#else
+	int mode = port->physport->ieee1284.mode;
+	size_t (*fn) (struct parport *, void *, size_t, int);
+
+	/* Ignore the device-ID-request bit. */
+	mode &= ~IEEE1284_DEVICEID;
+
+	/* Use the mode we're in. */
+	switch (mode) {
+	case IEEE1284_MODE_COMPAT:
+		if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
+			return -EIO;
+	case IEEE1284_MODE_NIBBLE:
+		DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
+		fn = port->ops->nibble_read_data;
+		break;
+
+	case IEEE1284_MODE_BYTE:
+		DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
+		fn = port->ops->byte_read_data;
+		break;
+
+	case IEEE1284_MODE_EPP:
+		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+		fn = port->ops->epp_read_data;
+		break;
+
+	case IEEE1284_MODE_ECP:
+	case IEEE1284_MODE_ECPRLE:
+		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+		fn = port->ops->ecp_read_data;
+		break;
+
+	case IEEE1284_MODE_ECPSWE:
+		DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+			 port->name);
+		fn = parport_ieee1284_ecp_read_data;
+		break;
+
+	default:
+		DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+			 port->physport->ieee1284.mode);
+		return -ENOSYS;
+	}
+
+	return (*fn) (port, buffer, len, 0);
+#endif /* IEEE1284 support */
+}
+
+/* Set the amount of time we wait while nothing's happening. */
+long parport_set_timeout (struct pardevice *dev, long inactivity)
+{
+	long int old = dev->timeout;
+
+	dev->timeout = inactivity;
+
+	if (dev->port->physport->cad == dev)
+		parport_ieee1284_wakeup (dev->port);
+
+	return old;
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_ieee1284_ops.c linux/drivers/misc/parport_ieee1284_ops.c
--- v2.3.9/linux/drivers/misc/parport_ieee1284_ops.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_ieee1284_ops.c	Tue Jul  6 19:08:33 1999
@@ -0,0 +1,848 @@
+/* IEEE-1284 operations for parport.
+ *
+ * This file is for generic IEEE 1284 operations.  The idea is that
+ * they are used by the low-level drivers.  If they have a special way
+ * of doing something, they can provide their own routines (and put
+ * the function pointers in port->ops); if not, they can just use these
+ * as a fallback.
+ *
+ * Note: Make no assumptions about hardware or architecture in this file!
+ *
+ * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ */
+
+#include <linux/config.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/***                                *
+ * One-way data transfer functions. *
+ *                                ***/
+
+static inline
+int polling (struct pardevice *dev)
+{
+	return dev->port->irq == PARPORT_IRQ_NONE;
+}
+
+/* Compatibility mode. */
+size_t parport_ieee1284_write_compat (struct parport *port,
+				      const void *buffer, size_t len,
+				      int flags)
+{
+	ssize_t count = 0;
+	const unsigned char *addr = buffer;
+	unsigned char byte;
+	struct pardevice *dev = port->physport->cad;
+	unsigned char ctl = (PARPORT_CONTROL_SELECT
+			     | PARPORT_CONTROL_INIT);
+
+	if (port->irq != PARPORT_IRQ_NONE)
+		parport_enable_irq (port);
+
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+	while (count < len) {
+		long expire = jiffies + dev->timeout;
+		long wait = (HZ + 99) / 100;
+		unsigned char mask = (PARPORT_STATUS_ERROR
+				      | PARPORT_STATUS_BUSY);
+		unsigned char val = (PARPORT_STATUS_ERROR
+				     | PARPORT_STATUS_BUSY);
+		int i;
+
+		/* Write the character to the data lines. */
+		byte = *addr++;
+		parport_write_data (port, byte);
+		udelay (1);
+
+		/* Wait until the peripheral's ready */
+		do {
+			/* Is the peripheral ready yet? */
+			if (!parport_wait_peripheral (port, mask, val))
+				/* Skip the loop */
+				goto ready;
+
+			/* Is the peripheral upset? */
+			if ((parport_read_status (port) &
+			     (PARPORT_STATUS_PAPEROUT |
+			      PARPORT_STATUS_SELECT |
+			      PARPORT_STATUS_ERROR))
+			    != (PARPORT_STATUS_SELECT |
+				PARPORT_STATUS_ERROR))
+				/* If nFault is asserted (i.e. no
+				 * error) and PAPEROUT and SELECT are
+				 * just red herrings, give the driver
+				 * a chance to check it's happy with
+				 * that before continuing. */
+				goto stop;
+
+			/* Have we run out of time? */
+			if (!time_before (jiffies, expire))
+				break;
+
+			/* Yield the port for a while.  If this is the
+                           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)) {
+				parport_release (dev);
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout (wait);
+				parport_claim_or_block (dev);
+			}
+			else
+				/* We must have the device claimed here */
+				parport_wait_event (port, wait);
+
+			/* Is there a signal pending? */
+			if (signal_pending (current))
+				goto stop;
+
+			/* Wait longer next time. */
+			wait *= 2;
+		} while (time_before (jiffies, expire));
+
+		DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
+		break;
+
+	ready:
+		/* Clear out previous irqs. */
+		while (!down_trylock (&port->physport->ieee1284.irq));
+
+		/* Pulse strobe. */
+		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		udelay (1); /* strobe */
+
+		parport_write_control (port, ctl);
+		udelay (1); /* hold */
+
+		/* Wait until it's received (up to 20us). */
+		for (i = 0; i < 20; i++) {
+			if (!down_trylock (&port->physport->ieee1284.irq) ||
+			    !(parport_read_status (port) & PARPORT_STATUS_ACK))
+				break;
+			udelay (1);
+		}
+
+		count++;
+
+                /* Let another process run if it needs to. */
+		if (time_before (jiffies, expire))
+			if (!parport_yield_blocking (dev)
+			    && current->need_resched)
+				schedule ();
+	}
+ stop:
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return count;
+}
+
+/* Nibble mode. */
+size_t parport_ieee1284_read_nibble (struct parport *port, 
+				     void *buffer, size_t len,
+				     int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	unsigned char *buf = buffer;
+	int i;
+	unsigned char byte = 0;
+
+	len *= 2; /* in nibbles */
+	for (i=0; i < len; i++) {
+		unsigned char nibble;
+
+		/* Does the error line indicate end of data? */
+		if (((i & 1) == 0) &&
+		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
+			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+			DPRINTK (KERN_DEBUG
+				"%s: No more nibble data (%d bytes)\n",
+				port->name, i/2);
+
+			/* Go to reverse idle phase. */
+			parport_frob_control (port,
+					      PARPORT_CONTROL_AUTOFD,
+					      PARPORT_CONTROL_AUTOFD);
+			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+			break;
+		}
+
+		/* Event 7: Set nAutoFd low. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 9: nAck goes low. */
+		port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK, 0)) {
+			/* Timeout -- no more data? */
+			DPRINTK (KERN_DEBUG
+				 "%s: Nibble timeout at event 9 (%d bytes)\n",
+				 port->name, i/2);
+			break;
+		}
+
+
+		/* Read a nibble. */
+		nibble = parport_read_status (port) >> 3;
+		nibble &= ~8;
+		if ((nibble & 0x10) == 0)
+			nibble |= 8;
+		nibble &= 0xf;
+
+		/* Event 10: Set nAutoFd high. */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+		/* Event 11: nAck goes high. */
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK,
+					     PARPORT_STATUS_ACK)) {
+			/* Timeout -- no more data? */
+			DPRINTK (KERN_DEBUG
+				 "%s: Nibble timeout at event 11\n",
+				 port->name);
+			break;
+		}
+
+		if (i & 1) {
+			/* Second nibble */
+			byte |= nibble << 4;
+			*buf++ = byte;
+		} else 
+			byte = nibble;
+	}
+
+	i /= 2; /* i is now in bytes */
+
+	if (i == len) {
+		/* Read the last nibble without checking data avail. */
+		port = port->physport;
+		if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+		else
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+	}
+
+	return i;
+#endif /* IEEE1284 support */
+}
+
+/* Byte mode. */
+size_t parport_ieee1284_read_byte (struct parport *port,
+				   void *buffer, size_t len,
+				   int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	unsigned char *buf = buffer;
+	ssize_t count = 0;
+
+	for (count = 0; count < len; count++) {
+		unsigned char byte;
+
+		/* Data available? */
+		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
+			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+			DPRINTK (KERN_DEBUG
+				 "%s: No more byte data (%d bytes)\n",
+				 port->name, count);
+
+			/* Go to reverse idle phase. */
+			parport_frob_control (port,
+					      PARPORT_CONTROL_AUTOFD,
+					      PARPORT_CONTROL_AUTOFD);
+			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+			break;
+		}
+
+		/* Event 7: Set nAutoFd low. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 9: nAck goes low. */
+		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK,
+					     0)) {
+			/* Timeout -- no more data? */
+			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+						 0);
+			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
+				 port->name);
+			break;
+		}
+
+		byte = parport_read_data (port);
+		*buf++ = byte;
+
+		/* Event 10: Set nAutoFd high */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+		/* Event 11: nAck goes high. */
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK,
+					     PARPORT_STATUS_ACK)) {
+			/* Timeout -- no more data? */
+			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
+				 port->name);
+			break;
+		}
+
+		/* Event 16: Set nStrobe low. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+		udelay (5);
+
+		/* Event 17: Set nStrobe high. */
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+	}
+
+	if (count == len) {
+		/* Read the last byte without checking data avail. */
+		port = port->physport;
+		if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+		else
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+	}
+
+	return count;
+#endif /* IEEE1284 support */
+}
+
+/***              *
+ * ECP Functions. *
+ *              ***/
+
+#ifdef CONFIG_PARPORT_1284
+
+static inline
+int ecp_forward_to_reverse (struct parport *port)
+{
+	int retval;
+
+	/* Event 38: Set nAutoFd low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_AUTOFD);
+	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);
+
+	/* Event 40: PError goes low */
+	retval = parport_wait_peripheral (port,
+					  PARPORT_STATUS_PAPEROUT, 0);
+
+	if (!retval) {
+		DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+	}
+
+	return retval;
+}
+
+static inline
+int ecp_reverse_to_forward (struct parport *port)
+{
+	int retval;
+
+	/* Event 47: Set nInit high */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
+	parport_data_reverse (port);
+
+	/* Event 49: PError goes high */
+	retval = parport_wait_peripheral (port,
+					  PARPORT_STATUS_PAPEROUT,
+					  PARPORT_STATUS_PAPEROUT);
+
+	if (!retval) {
+		parport_data_forward (port);
+		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	}
+
+	return retval;
+}
+
+#endif /* IEEE1284 support */
+
+/* ECP mode, forward channel, data. */
+size_t parport_ieee1284_ecp_write_data (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	const unsigned char *buf = buffer;
+	size_t written;
+	int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
+	int retry;
+
+	port = port->physport;
+
+	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+		if (ecp_reverse_to_forward (port))
+			return 0;
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* HostAck high (data, not command) */
+	parport_write_control (port, ctl);
+	for (written = 0; written < len; written++, buf++) {
+		long expire = jiffies + port->cad->timeout;
+		unsigned char byte;
+
+		byte = *buf;
+	try_again:
+		parport_write_data (port, byte);
+		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		udelay (5);
+		for (retry = 0; retry < 100; retry++) {
+			if (!parport_wait_peripheral (port,
+						      PARPORT_STATUS_BUSY, 0))
+				goto success;
+
+			if (signal_pending (current)) {
+				parport_write_control (port, ctl);
+				break;
+			}
+		}
+
+		/* 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);
+		udelay (50);
+		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+			/* It's buggered. */
+			parport_write_control (port, ctl);
+			break;
+		}
+
+		parport_write_control (port, ctl);
+		udelay (50);
+		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+			break;
+
+		DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+			 port->name);
+
+		if (time_after_eq (jiffies, expire)) break;
+		goto try_again;
+	success:
+		parport_write_control (port, ctl);
+		udelay (5);
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			/* Peripheral hasn't accepted the data. */
+			break;
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, reverse channel, data. */
+size_t parport_ieee1284_ecp_read_data (struct parport *port,
+				       void *buffer, size_t len, int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	struct pardevice *dev = port->cad;
+	unsigned char *buf = buffer;
+	int rle_count = 0; /* shut gcc up */
+	int rle = 0;
+	ssize_t count = 0;
+
+	port = port->physport;
+
+	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
+		if (ecp_forward_to_reverse (port))
+			return 0;
+
+	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+	/* Set HostAck low to start accepting data. */
+	parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_AUTOFD);
+	while (count < len) {
+		long expire = jiffies + dev->timeout;
+		unsigned char byte;
+		int command;
+
+		/* 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)) {
+			/* The peripheral hasn't given us data in
+			   35ms.  If we have data to give back to the
+			   caller, do it now. */
+			if (count)
+				goto out;
+
+			/* If we've used up all the time we were allowed,
+			   give up altogether. */
+			if (!time_before (jiffies, expire))
+				goto out;
+
+			/* Yield the port for a while. */
+			if (count && polling (dev)) {
+				parport_release (dev);
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout ((HZ + 99) / 25);
+				parport_claim_or_block (dev);
+			}
+			else
+				/* We must have the device claimed here. */
+				parport_wait_event (port, (HZ + 99) / 25);
+
+			/* Is there a signal pending? */
+			if (signal_pending (current))
+				goto out;
+		}
+
+		/* Is this a command? */
+		if (rle)
+			/* The last byte was a run-length count, so
+                           this can't be as well. */
+			command = 0;
+		else
+			command = (parport_read_status (port) &
+				   PARPORT_STATUS_BUSY) ? 1 : 0;
+
+		/* Read the data. */
+		byte = parport_read_data (port);
+
+		/* If this is a channel command, rather than an RLE
+                   command or a normal data byte, don't accept it. */
+		if (command) {
+			if (byte & 0x80) {
+				DPRINTK (KERN_DEBUG "%s: stopping short at "
+					 "channel command (%02x)\n",
+					 port->name, byte);
+				goto out;
+			}
+			else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
+				DPRINTK (KERN_DEBUG "%s: device illegally "
+					 "using RLE; accepting anyway\n",
+					 port->name);
+
+			rle_count = byte + 1;
+
+			/* Are we allowed to read that many bytes? */
+			if (rle_count > (len - count)) {
+				DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
+					 "for next time\n", port->name,
+					 rle_count);
+				break;
+			}
+
+			rle = 1;
+		}
+
+		/* Event 44: Set HostAck high, acknowledging handshake. */
+		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)) {
+			/* It's gone wrong.  Return what data we have
+                           to the caller. */
+			DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
+
+			if (command)
+				printk (KERN_WARNING
+					"%s: command ignored (%02x)\n",
+					port->name, byte);
+
+			break;
+		}
+
+		/* Event 46: Set HostAck low and accept the data. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* If we just read a run-length count, fetch the data. */
+		if (command)
+			continue;
+
+		/* If this is the byte after a run-length count, decompress. */
+		if (rle) {
+			rle = 0;
+			memset (buf, byte, rle_count);
+			buf += rle_count;
+			count += rle_count;
+			DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
+				 port->name, rle_count);
+		}
+		else
+			/* Normal data byte. */
+			*buf++ = byte, count++;
+	}
+
+ out:
+	return count;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, forward channel, commands. */
+size_t parport_ieee1284_ecp_write_addr (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	const unsigned char *buf = buffer;
+	size_t written;
+	int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
+	int retry;
+
+	port = port->physport;
+
+	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+		if (ecp_reverse_to_forward (port))
+			return 0;
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* HostAck low (command, not data) */
+	parport_write_control (port, ctl);
+	for (written = 0; written < len; written++, buf++) {
+		long expire = jiffies + port->cad->timeout;
+		unsigned char byte;
+
+		byte = *buf;
+	try_again:
+		parport_write_data (port, byte);
+		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		udelay (5);
+		for (retry = 0; retry < 100; retry++) {
+			if (!parport_wait_peripheral (port,
+						      PARPORT_STATUS_BUSY, 0))
+				goto success;
+
+			if (signal_pending (current)) {
+				parport_write_control (port, ctl);
+				break;
+			}
+		}
+
+		/* 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);
+		udelay (50);
+		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+			/* It's buggered. */
+			parport_write_control (port, ctl);
+			break;
+		}
+
+		parport_write_control (port, ctl);
+		udelay (50);
+		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+			break;
+
+		DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+			 port->name);
+
+		if (time_after_eq (jiffies, expire)) break;
+		goto try_again;
+	success:
+		parport_write_control (port, ctl);
+		udelay (5);
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			/* Peripheral hasn't accepted the data. */
+			break;
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
+#endif /* IEEE1284 support */
+}
+
+/***              *
+ * EPP functions. *
+ *              ***/
+
+/* EPP mode, forward channel, data. */
+size_t parport_ieee1284_epp_write_data (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+	/* This is untested */
+	unsigned char *bp = (unsigned char *) buffer;
+	size_t ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT);
+	port->ops->data_forward (port);
+	for (; len > 0; len--, bp++) {
+		parport_write_data (port, *bp);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		/* Strobe data */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+		ret++;
+	}
+
+	return ret;
+}
+
+/* EPP mode, reverse channel, data. */
+size_t parport_ieee1284_epp_read_data (struct parport *port,
+				       void *buffer, size_t len,
+				       int flags)
+{
+	/* This is untested. */
+	unsigned char *bp = (unsigned char *) buffer;
+	unsigned ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT, 0);
+	port->ops->data_reverse (port);
+	for (; len > 0; len--, bp++) {
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		*bp = parport_read_data (port);
+
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+		ret++;
+	}
+	port->ops->data_forward (port);
+
+	return ret;
+}
+
+/* EPP mode, forward channel, addresses. */
+size_t parport_ieee1284_epp_write_addr (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+	/* This is untested */
+	unsigned char *bp = (unsigned char *) buffer;
+	size_t ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT);
+	port->ops->data_forward (port);
+	for (; len > 0; len--, bp++) {
+		parport_write_data (port, *bp);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		/* Strobe data */
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		ret++;
+	}
+
+	return ret;
+}
+
+/* EPP mode, reverse channel, addresses. */
+size_t parport_ieee1284_epp_read_addr (struct parport *port,
+				       void *buffer, size_t len,
+				       int flags)
+{
+	/* This is untested. */
+	unsigned char *bp = (unsigned char *) buffer;
+	unsigned ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_AUTOFD, 0);
+	port->ops->data_reverse (port);
+	for (; len > 0; len--, bp++) {
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		*bp = parport_read_data (port);
+
+		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		ret++;
+	}
+	port->ops->data_forward (port);
+
+	return ret;
+}
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.3.9/linux/drivers/misc/parport_init.c	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/parport_init.c	Sun Jul  4 10:14:13 1999
@@ -22,7 +22,7 @@
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
-static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_AUTO };
+static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
 
 extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
 extern int parport_ax_init(void);
@@ -119,10 +119,7 @@
 	if (io[0] == PARPORT_DISABLE) 
 		return 1;
 
-#ifdef CONFIG_PNP_PARPORT
-	parport_probe_hook = &parport_probe_one;
-#endif
-#ifdef	CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL
 	parport_default_proc_register ();
 #endif
 
@@ -161,13 +158,42 @@
 EXPORT_SYMBOL(parport_register_device);
 EXPORT_SYMBOL(parport_unregister_device);
 EXPORT_SYMBOL(parport_enumerate);
-EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
+EXPORT_SYMBOL(parport_negotiate);
+EXPORT_SYMBOL(parport_write);
+EXPORT_SYMBOL(parport_read);
+EXPORT_SYMBOL(parport_ieee1284_wakeup);
 EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_wait_event);
+EXPORT_SYMBOL(parport_set_timeout);
+EXPORT_SYMBOL(parport_ieee1284_interrupt);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_write_compat);
+EXPORT_SYMBOL(parport_ieee1284_read_nibble);
+EXPORT_SYMBOL(parport_ieee1284_read_byte);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
-EXPORT_SYMBOL(parport_probe_hook);
+EXPORT_SYMBOL(parport_device_proc_register);
+EXPORT_SYMBOL(parport_device_proc_unregister);
+EXPORT_SYMBOL(parport_default_proc_register);
+EXPORT_SYMBOL(parport_default_proc_unregister);
 EXPORT_SYMBOL(parport_parse_irqs);
 EXPORT_SYMBOL(parport_parse_dmas);
+#ifdef CONFIG_PARPORT_1284
+EXPORT_SYMBOL(parport_open);
+EXPORT_SYMBOL(parport_close);
+EXPORT_SYMBOL(parport_device_id);
+EXPORT_SYMBOL(parport_device_num);
+EXPORT_SYMBOL(parport_device_coords);
+EXPORT_SYMBOL(parport_daisy_deselect_all);
+EXPORT_SYMBOL(parport_daisy_select);
+EXPORT_SYMBOL(parport_daisy_init);
+#endif
 
 void inc_parport_count(void)
 {
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.3.9/linux/drivers/misc/parport_pc.c	Mon Jun  7 13:25:18 1999
+++ linux/drivers/misc/parport_pc.c	Wed Jul  7 12:55:47 1999
@@ -9,6 +9,7 @@
  * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
  *
  * 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>
  */
 
@@ -46,9 +47,11 @@
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/pci.h>
+#include <linux/sysctl.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
+#include <asm/uaccess.h>
 
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
@@ -57,12 +60,138 @@
    than PARPORT_MAX (in <linux/parport.h>).  */
 #define PARPORT_PC_MAX_PORTS  8
 
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+#define ECR_VND 05
+#define ECR_TST 06
+#define ECR_CNF 07
+
 static int user_specified __initdata = 0;
 
+/* frob_control, but for ECR */
+static void frob_econtrol (struct parport *pb, unsigned char m,
+			   unsigned char v)
+{
+	outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *p, int m)
+{
+	const struct parport_pc_private *priv = p->physport->private_data;
+	int ecr = ECONTROL(p);
+	unsigned char oecr;
+	int mode;
+
+	if (!priv->ecr) {
+		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
+		return 0;
+	}
+
+	/* Bits <7:5> contain the mode. */
+	oecr = inb (ecr);
+	mode = (oecr >> 5) & 0x7;
+	if (mode == m) return 0;
+	if (mode && m)
+		/* We have to go through mode 000 */
+		change_mode (p, ECR_SPP);
+
+	if (m < 2 && !(parport_read_control (p) & 0x20)) {
+		/* This mode resets the FIFO, so we may
+		 * have to wait for it to drain first. */
+		long expire = jiffies + p->physport->cad->timeout;
+		int counter;
+		switch (mode) {
+		case ECR_PPF: /* Parallel Port FIFO mode */
+		case ECR_ECP: /* ECP Parallel Port mode */
+			/* Busy wait for 200us */
+			for (counter = 0; counter < 40; counter++) {
+				if (inb (ECONTROL (p)) & 0x01)
+					break;
+				if (signal_pending (current)) break;
+				udelay (5);
+			}
+
+			/* Poll slowly. */
+			while (!(inb (ECONTROL (p)) & 0x01)) {
+				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. */
+	oecr &= ~(7 << 5);
+	oecr |= m << 5;
+	outb (oecr, ecr);
+	return 0;
+}
+
+/* Find FIFO lossage; FIFO is reset */
+static int get_fifo_residue (struct parport *p)
+{
+	int residue;
+	int cnfga;
+	const struct parport_pc_private *priv = p->physport->private_data;
+
+	/* Prevent further data transfer. */
+	parport_frob_control (p,
+			      PARPORT_CONTROL_STROBE,
+			      PARPORT_CONTROL_STROBE);
+
+	/* Adjust for the contents of the FIFO. */
+	for (residue = priv->fifo_depth; ; residue--) {
+		if (inb (ECONTROL (p)) & 0x2)
+				/* Full up. */
+			break;
+
+		outb (0, FIFO (p));
+	}
+
+	printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
+		residue);
+
+	/* Reset the FIFO. */
+	frob_econtrol (p, 0xe0, 0x20);
+	parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
+
+	/* Now change to config mode and clean up. FIXME */
+	frob_econtrol (p, 0xe0, 0xe0);
+	cnfga = inb (CONFIGA (p));
+	printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
+
+	if (!(cnfga & (1<<2))) {
+		printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
+		residue++;
+	}
+
+	/* Don't care about partial PWords until support is added for
+	 * PWord != 1 byte. */
+
+	/* Back to PS2 mode. */
+	frob_econtrol (p, 0xe0, 0x20);
+
+	return residue;
+}
+
+#endif /* IEEE 1284 support */
+
 /*
  * Clear TIMEOUT BIT in EPP MODE
+ *
+ * This is also used in SPP detection.
  */
-int parport_pc_epp_clear_timeout(struct parport *pb)
+static int clear_epp_timeout(struct parport *pb)
 {
 	unsigned char r;
 
@@ -72,187 +201,719 @@
 	/* To clear timeout some chips require double read */
 	parport_pc_read_status(pb);
 	r = parport_pc_read_status(pb);
-	parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */
-	parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */
+	outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
+	outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
 	r = parport_pc_read_status(pb);
 
 	return !(r & 0x01);
 }
 
+/*
+ * Access functions.
+ *
+ * These aren't static because they may be used by the parport_xxx_yyy
+ * macros.  extern __inline__ versions of several of these are in
+ * parport_pc.h.
+ */
+
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
-void parport_pc_write_epp(struct parport *p, unsigned char d)
+void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-	outb(d, EPPDATA(p));
+	outb (d, DATA (p));
 }
 
-unsigned char parport_pc_read_epp(struct parport *p)
+unsigned char parport_pc_read_data(struct parport *p)
 {
-	return inb(EPPDATA(p));
+	return inb (DATA (p));
 }
 
-void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+unsigned char __frob_control (struct parport *p, unsigned char mask,
+			      unsigned char val)
 {
-	outb(d, EPPADDR(p));
+	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 */
 }
 
-unsigned char parport_pc_read_epp_addr(struct parport *p)
+void parport_pc_write_control(struct parport *p, unsigned char d)
 {
-	return inb(EPPADDR(p));
-}
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to the newer interface. */
+	if (d & 0x20) {
+			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+					p->name, p->cad->name);
+			parport_pc_data_reverse (p);
+	}
 
-int parport_pc_check_epp_timeout(struct parport *p)
-{
-	if (!(inb(STATUS(p)) & 1))
-		return 0;
-	parport_pc_epp_clear_timeout(p);
-	return 1;
+	__frob_control (p, wm, d & wm);
 }
 
-unsigned char parport_pc_read_configb(struct parport *p)
+unsigned char parport_pc_read_control(struct parport *p)
 {
-	return inb(CONFIGB(p));
+	const struct parport_pc_private *priv = p->physport->private_data;
+	return priv->ctr; /* Use soft copy */
 }
 
-void parport_pc_write_data(struct parport *p, unsigned char d)
+unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
+				       unsigned char val)
 {
-	outb(d, DATA(p));
-}
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to the newer interface. */
+	if (mask & 0x20) {
+			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+					p->name, p->cad->name);
+			parport_pc_data_reverse (p);
+	}
 
-unsigned char parport_pc_read_data(struct parport *p)
-{
-	return inb(DATA(p));
+	/* Restrict mask and val to control lines. */
+	mask &= wm;
+	val &= wm;
+
+	return __frob_control (p, mask, val);
 }
 
-void parport_pc_write_control(struct parport *p, unsigned char d)
+unsigned char parport_pc_read_status(struct parport *p)
 {
-	struct parport_pc_private *priv = p->private_data;
-	priv->ctr = d;/* update soft copy */
-	outb(d, CONTROL(p));
+	return inb (STATUS (p));
 }
 
-unsigned char parport_pc_read_control(struct parport *p)
+void parport_pc_disable_irq(struct parport *p)
 {
-	struct parport_pc_private *priv = p->private_data;
-	return priv->ctr;
+	__frob_control (p, 0x10, 0);
 }
 
-unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
+void parport_pc_enable_irq(struct parport *p)
 {
-	struct parport_pc_private *priv = p->private_data;
-	unsigned char ctr = priv->ctr;
-	ctr = (ctr & ~mask) ^ val;
-	outb (ctr, CONTROL(p));
-	return priv->ctr = ctr; /* update soft copy */
+	__frob_control (p, 0x10, 0x10);
 }
 
-void parport_pc_write_status(struct parport *p, unsigned char d)
+void parport_pc_data_forward (struct parport *p)
 {
-	outb(d, STATUS(p));
+	__frob_control (p, 0x20, 0);
 }
 
-unsigned char parport_pc_read_status(struct parport *p)
+void parport_pc_data_reverse (struct parport *p)
 {
-	return inb(STATUS(p));
+	__frob_control (p, 0x20, 0x20);
 }
 
-void parport_pc_write_econtrol(struct parport *p, unsigned char d)
+void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
 {
-	outb(d, ECONTROL(p));
+	struct parport_pc_private *priv = dev->port->physport->private_data;
+	priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+	s->u.pc.ecr = 0x24;
 }
 
-unsigned char parport_pc_read_econtrol(struct parport *p)
+void parport_pc_save_state(struct parport *p, struct parport_state *s)
 {
-	return inb(ECONTROL(p));
+	const struct parport_pc_private *priv = p->physport->private_data;
+	s->u.pc.ctr = inb (CONTROL (p));
+	if (priv->ecr)
+		s->u.pc.ecr = inb (ECONTROL (p));
 }
 
-unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
+void parport_pc_restore_state(struct parport *p, struct parport_state *s)
 {
-	unsigned char old = inb(ECONTROL(p));
-	outb(((old & ~mask) ^ val), ECONTROL(p));
-	return old;
+	const struct parport_pc_private *priv = p->physport->private_data;
+	outb (s->u.pc.ctr, CONTROL (p));
+	if (priv->ecr)
+		outb (s->u.pc.ecr, ECONTROL (p));
 }
 
-void parport_pc_change_mode(struct parport *p, int m)
+#ifdef CONFIG_PARPORT_1284
+static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
+					size_t length, int flags)
 {
-	/* FIXME */
+	size_t got = 0;
+	for (; got < length; got++) {
+		*((char*)buf)++ = inb (EPPDATA(port));
+		if (inb (STATUS(port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return got;
 }
 
-void parport_pc_write_fifo(struct parport *p, unsigned char v)
+static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
+					 size_t length, int flags)
 {
-	outb (v, CONFIGA(p));
+	size_t written = 0;
+	for (; written < length; written++) {
+		outb (*((char*)buf)++, EPPDATA(port));
+		if (inb (STATUS(port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return written;
 }
 
-unsigned char parport_pc_read_fifo(struct parport *p)
+static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
+					size_t length, int flags)
 {
-	return inb (CONFIGA(p));
+	size_t got = 0;
+	for (; got < length; got++) {
+		*((char*)buf)++ = inb (EPPADDR (port));
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return got;
 }
 
-void parport_pc_disable_irq(struct parport *p)
+static size_t parport_pc_epp_write_addr (struct parport *port,
+					 const void *buf, size_t length,
+					 int flags)
 {
-	parport_pc_frob_control(p, 0x10, 0);
+	size_t written = 0;
+	for (; written < length; written++) {
+		outb (*((char*)buf)++, EPPADDR (port));
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return written;
 }
 
-void parport_pc_enable_irq(struct parport *p)
+static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
+					   size_t length, int flags)
 {
-	parport_pc_frob_control(p, 0x10, 0x10);
+	size_t got;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	got = parport_pc_epp_read_data (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return got;
 }
 
-void parport_pc_init_state(struct parport_state *s)
-{
-	s->u.pc.ctr = 0xc;
-	s->u.pc.ecr = 0x0;
+static size_t parport_pc_ecpepp_write_data (struct parport *port,
+					    const void *buf, size_t length,
+					    int flags)
+{
+	size_t written;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	written = parport_pc_epp_write_data (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return written;
 }
 
-void parport_pc_save_state(struct parport *p, struct parport_state *s)
+static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
+					   size_t length, int flags)
 {
-	s->u.pc.ctr = parport_pc_read_control(p);
-	if (p->modes & PARPORT_MODE_PCECR)
-		s->u.pc.ecr = parport_pc_read_econtrol(p);
+	size_t got;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	got = parport_pc_epp_read_addr (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return got;
 }
 
-void parport_pc_restore_state(struct parport *p, struct parport_state *s)
-{
-	parport_pc_write_control(p, s->u.pc.ctr);
-	if (p->modes & PARPORT_MODE_PCECR)
-		parport_pc_write_econtrol(p, s->u.pc.ecr);
+static size_t parport_pc_ecpepp_write_addr (struct parport *port,
+					    const void *buf, size_t length,
+					    int flags)
+{
+	size_t written;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	written = parport_pc_epp_write_addr (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return written;
 }
+#endif /* IEEE 1284 support */
 
-size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length)
-{
-	size_t got = 0;
-	for (; got < length; got++) {
-		*((char*)buf)++ = inb (EPPDATA(p));
-		if (inb (STATUS(p)) & 0x01)
+#ifdef CONFIG_PARPORT_PC_FIFO
+static size_t parport_pc_fifo_write_block_pio (struct parport *port,
+					       const void *buf, size_t length)
+{
+	int ret = 0;
+	const unsigned char *bufp = buf;
+	size_t left = length;
+	long expire = jiffies + port->physport->cad->timeout;
+	const int fifo = FIFO (port);
+	int poll_for = 8; /* 80 usecs */
+	const struct parport_pc_private *priv = port->physport->private_data;
+	const int fifo_depth = priv->fifo_depth;
+
+	port = port->physport;
+
+	/* We don't want to be interrupted every character. */
+	parport_pc_disable_irq (port);
+	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+	/* Forward mode. */
+	parport_pc_data_forward (port);
+
+	while (left) {
+		unsigned char byte;
+		unsigned char ecrval = inb (ECONTROL (port));
+		int i = 0;
+
+		if (current->need_resched && time_before (jiffies, expire))
+			/* Can't yield the port. */
+			schedule ();
+
+		/* Anyone else waiting for the port? */
+		if (port->waithead) {
+			printk (KERN_DEBUG "Somebody wants the port\n");
 			break;
-	}
-	return got;
+		}
+
+		if (ecrval & 0x02) {
+			/* FIFO is full. Wait for interrupt. */
+
+			/* Clear serviceIntr */
+			outb (ecrval & ~(1<<2), ECONTROL (port));
+		false_alarm:
+			ret = parport_wait_event (port, HZ);
+			if (ret < 0) break;
+			ret = 0;
+			if (!time_before (jiffies, expire)) {
+				/* Timed out. */
+				printk (KERN_DEBUG "Timed out\n");
+				break;
+			}
+			ecrval = inb (ECONTROL (port));
+			if (!(ecrval & (1<<2))) {
+				if (current->need_resched &&
+				    time_before (jiffies, expire))
+					schedule ();
+
+				goto false_alarm;
+			}
+
+			continue;
+		}
+
+		/* Can't fail now. */
+		expire = jiffies + port->cad->timeout;
+
+	poll:
+		if (signal_pending (current))
+			break;
+
+		if (ecrval & 0x01) {
+			/* FIFO is empty. Blast it full. */
+			const int n = left < fifo_depth ? left : fifo_depth;
+			outsb (fifo, bufp, n);
+			bufp += n;
+			left -= n;
+
+			/* Adjust the poll time. */
+			if (i < (poll_for - 2)) poll_for--;
+			continue;
+		} else if (i++ < poll_for) {
+			udelay (10);
+			ecrval = inb (ECONTROL (port));
+			goto poll;
+		}
+
+		/* Half-full (call me an optimist) */
+		byte = *bufp++;
+		outb (byte, fifo);
+		left--;
+        }
+
+	return length - left;
 }
 
-size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length)
+static size_t parport_pc_fifo_write_block_dma (struct parport *port,
+					       const void *buf, size_t length)
 {
-	size_t written = 0;
-	for (; written < length; written++) {
-		outb (*((char*)buf)++, EPPDATA(p));
-		if (inb (STATUS(p)) & 0x01)
+	int ret = 0;
+	unsigned long dmaflag;
+	size_t left  = length;
+	const struct parport_pc_private *priv = port->physport->private_data;
+
+	port = port->physport;
+
+	/* We don't want to be interrupted every character. */
+	parport_pc_disable_irq (port);
+	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+	/* Forward mode. */
+	parport_pc_data_forward (port);
+
+	while (left) {
+		long expire = jiffies + port->physport->cad->timeout;
+
+		size_t count = left;
+
+		if (count > PAGE_SIZE)
+			count = PAGE_SIZE;
+
+		memcpy(priv->dma_buf, buf, count);
+
+		dmaflag = claim_dma_lock();
+		disable_dma(port->dma);
+		clear_dma_ff(port->dma);
+		set_dma_mode(port->dma, DMA_MODE_WRITE);
+		set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf));
+		set_dma_count(port->dma, count);
+
+		/* Set DMA mode */
+		frob_econtrol (port, 1<<3, 1<<3);
+
+		/* Clear serviceIntr */
+		frob_econtrol (port, 1<<2, 0);
+
+		enable_dma(port->dma);
+		release_dma_lock(dmaflag);
+
+		/* assume DMA will be successful */
+		left -= count;
+		buf  += count;
+
+		/* Wait for interrupt. */
+	false_alarm:
+		ret = parport_wait_event (port, HZ);
+		if (ret < 0) break;
+		ret = 0;
+		if (!time_before (jiffies, expire)) {
+			/* Timed out. */
+			printk (KERN_DEBUG "Timed out\n");
+			break;
+		}
+		/* Is serviceIntr set? */
+		if (!(inb (ECONTROL (port)) & (1<<2))) {
+			if (current->need_resched)
+				schedule ();
+
+			goto false_alarm;
+		}
+
+		dmaflag = claim_dma_lock();
+		disable_dma(port->dma);
+		clear_dma_ff(port->dma);
+		count = get_dma_residue(port->dma);
+		release_dma_lock(dmaflag);
+
+		if (current->need_resched)
+			/* Can't yield the port. */
+			schedule ();
+
+		/* Anyone else waiting for the port? */
+		if (port->waithead) {
+			printk (KERN_DEBUG "Somebody wants the port\n");
 			break;
+		}
+
+		/* update for possible DMA residue ! */
+		buf  -= count;
+		left += count;
 	}
+
+	/* Maybe got here through break, so adjust for DMA residue! */
+	dmaflag = claim_dma_lock();
+	disable_dma(port->dma);
+	clear_dma_ff(port->dma);
+	left += get_dma_residue(port->dma);
+	release_dma_lock(dmaflag);
+
+	/* Turn off DMA mode */
+	frob_econtrol (port, 1<<3, 0);
+
+	return length - left;
+}
+
+/* Parallel Port FIFO mode (ECP chipsets) */
+size_t parport_pc_compat_write_block_pio (struct parport *port,
+					  const void *buf, size_t length,
+					  int flags)
+{
+	size_t written;
+
+	/* Special case: a timeout of zero means we cannot call schedule(). */
+	if (!port->physport->cad->timeout)
+		return parport_ieee1284_write_compat (port, buf,
+						      length, flags);
+
+	/* Set up parallel port FIFO mode.*/
+	change_mode (port, ECR_PPF); /* Parallel port FIFO */
+	parport_pc_data_forward (port);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* Write the data to the FIFO. */
+	if (port->dma != PARPORT_DMA_NONE)
+		written = parport_pc_fifo_write_block_dma (port, buf, length);
+	else
+		written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+	/* Finish up. */
+	if (change_mode (port, ECR_PS2) == -EBUSY) {
+		const struct parport_pc_private *priv = 
+			port->physport->private_data;
+
+		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+		/* Prevent further data transfer. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+
+		/* Adjust for the contents of the FIFO. */
+		for (written -= priv->fifo_depth; ; written++) {
+			if (inb (ECONTROL (port)) & 0x2)
+				/* Full up. */
+				break;
+
+			outb (0, FIFO (port));
+		}
+
+		/* Reset the FIFO. */
+		frob_econtrol (port, 0xe0, 0);
+
+		/* De-assert strobe. */
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+	}
+
+	parport_wait_peripheral (port,
+				 PARPORT_STATUS_BUSY,
+				 PARPORT_STATUS_BUSY);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
 	return written;
 }
 
-int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
-{
-	return -ENOSYS; /* FIXME */
+/* ECP */
+#ifdef CONFIG_PARPORT_1284
+size_t parport_pc_ecp_write_block_pio (struct parport *port,
+				       const void *buf, size_t length,
+				       int flags)
+{
+	size_t written;
+
+	/* Special case: a timeout of zero means we cannot call schedule(). */
+	if (!port->physport->cad->timeout)
+		return parport_ieee1284_ecp_write_data (port, buf,
+							length, flags);
+
+	/* Switch to forward mode if necessary. */
+	if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+		/* Event 47: Set nInit high. */
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+
+		/* Event 40: PError goes high. */
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_PAPEROUT,
+					 PARPORT_STATUS_PAPEROUT);
+	}
+
+	/* Set up ECP parallel port mode.*/
+	change_mode (port, ECR_ECP); /* ECP FIFO */
+	parport_pc_data_forward (port);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* Write the data to the FIFO. */
+	if (port->dma != PARPORT_DMA_NONE)
+		written = parport_pc_fifo_write_block_dma (port, buf, length);
+	else
+		written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+	/* Finish up. */
+	if (change_mode (port, ECR_PS2) == -EBUSY) {
+		const struct parport_pc_private *priv =
+			port->physport->private_data;
+
+		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+		/* Prevent further data transfer. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+
+		/* Adjust for the contents of the FIFO. */
+		for (written -= priv->fifo_depth; ; written++) {
+			if (inb (ECONTROL (port)) & 0x2)
+				/* Full up. */
+				break;
+
+			outb (0, FIFO (port));
+		}
+
+		/* Reset the FIFO. */
+		frob_econtrol (port, 0xe0, 0);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+
+		/* Host transfer recovery. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
+		parport_pc_data_reverse (port);
+		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_PAPEROUT,
+					 PARPORT_STATUS_PAPEROUT);
+	}
+
+	parport_wait_peripheral (port,
+				 PARPORT_STATUS_BUSY, 
+				 PARPORT_STATUS_BUSY);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
 }
 
-int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
+size_t parport_pc_ecp_read_block_pio (struct parport *port,
+				      void *buf, size_t length, int flags)
 {
-	return -ENOSYS; /* FIXME */
+	size_t left = length;
+	size_t fifofull;
+	const int fifo = FIFO(port);
+	const struct parport_pc_private *priv = port->physport->private_data;
+	const int fifo_depth = priv->fifo_depth;
+	char *bufp = buf;
+
+	port = port->physport;
+
+	/* Special case: a timeout of zero means we cannot call schedule(). */
+	if (!port->cad->timeout)
+		return parport_ieee1284_ecp_read_data (port, buf,
+						       length, flags);
+
+	fifofull = fifo_depth;
+	if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
+		/* If the peripheral is allowed to send RLE compressed
+		 * data, it is possible for a byte to expand to 128
+		 * bytes in the FIFO. */
+		fifofull = 128;
+
+	/* If the caller wants less than a full FIFO's worth of data,
+	 * go through software emulation.  Otherwise we may have to through
+	 * away data. */
+	if (length < fifofull)
+		return parport_ieee1284_ecp_read_data (port, buf,
+						       length, flags);
+
+	/* Switch to reverse mode if necessary. */
+	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+		/* Event 38: Set nAutoFd low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+		parport_pc_data_reverse (port);
+		udelay (5);
+
+		/* Event 39: Set nInit low to initiate bus reversal */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
+
+		/* Event 40: PError goes low */
+		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+	}
+
+	/* Set up ECP parallel port mode.*/
+	change_mode (port, ECR_ECP); /* ECP FIFO */
+	parport_pc_data_reverse (port);
+	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+	/* Do the transfer. */
+	while (left > fifofull) {
+		int ret;
+		long int expire = jiffies + port->cad->timeout;
+		unsigned char ecrval = inb (ECONTROL (port));
+
+		if (current->need_resched && time_before (jiffies, expire))
+			/* Can't yield the port. */
+			schedule ();
+
+		/* At this point, the FIFO may already be full.
+		 * Ideally, we'd be able to tell the port to hold on
+		 * for a second while we empty the FIFO, and we'd be
+		 * able to ensure that no data is lost.  I'm not sure
+		 * that's the case. :-(  It might be that you can play
+		 * games with STB, as in the forward case; someone should
+		 * look at a datasheet. */
+
+		if (ecrval & 0x01) {
+			/* FIFO is empty. Wait for interrupt. */
+
+			/* Anyone else waiting for the port? */
+			if (port->waithead) {
+				printk (KERN_DEBUG
+					"Somebody wants the port\n");
+				break;
+			}
+
+			/* Clear serviceIntr */
+			outb (ecrval & ~(1<<2), ECONTROL (port));
+		false_alarm:
+			ret = parport_wait_event (port, HZ);
+			if (ret < 0) break;
+			ret = 0;
+			if (!time_before (jiffies, expire)) {
+				/* Timed out. */
+				printk (KERN_DEBUG "Timed out\n");
+				break;
+			}
+			ecrval = inb (ECONTROL (port));
+			if (!(ecrval & (1<<2))) {
+				if (current->need_resched &&
+				    time_before (jiffies, expire))
+					schedule ();
+
+				goto false_alarm;
+			}
+
+			continue;
+		}
+
+		if (ecrval & 0x02) {
+			/* FIFO is full. */
+			insb (fifo, bufp, fifo_depth);
+			bufp += fifo_depth;
+			left -= fifo_depth;
+			continue;
+		}
+
+		*bufp++ = inb (fifo);
+		left--;
+	}
+
+	/* Finish up. */
+	if (change_mode (port, ECR_PS2) == -EBUSY) {
+		int lost = get_fifo_residue (port);
+		printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
+			lost);
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+	return length - left;
 }
 
+#endif /* IEEE 1284 support */
+
+#endif /* Allowed to use FIFO/DMA */
+
 void parport_pc_inc_use_count(void)
 {
 #ifdef MODULE
@@ -269,6 +930,7 @@
 
 static void parport_pc_fill_inode(struct inode *inode, int fill)
 {
+	/* Is this still needed? -tim */
 #ifdef MODULE
 	if (fill)
 		MOD_INC_USE_COUNT;
@@ -286,46 +948,39 @@
 	parport_pc_read_control,
 	parport_pc_frob_control,
 
-	parport_pc_write_econtrol,
-	parport_pc_read_econtrol,
-	parport_pc_frob_econtrol,
-
-	parport_pc_write_status,
 	parport_pc_read_status,
 
-	parport_pc_write_fifo,
-	parport_pc_read_fifo,
-	
-	parport_pc_change_mode,
-	
-	parport_pc_write_epp,
-	parport_pc_read_epp,
-	parport_pc_write_epp_addr,
-	parport_pc_read_epp_addr,
-	parport_pc_check_epp_timeout,
+	parport_pc_enable_irq,
+	parport_pc_disable_irq,
 
-	parport_pc_epp_write_block,
-	parport_pc_epp_read_block,
+	parport_pc_data_forward,
+	parport_pc_data_reverse,
 
-	parport_pc_ecp_write_block,
-	parport_pc_ecp_read_block,
-	
+	parport_pc_interrupt,
 	parport_pc_init_state,
 	parport_pc_save_state,
 	parport_pc_restore_state,
 
-	parport_pc_enable_irq,
-	parport_pc_disable_irq,
-	parport_pc_interrupt,
-
 	parport_pc_inc_use_count,
 	parport_pc_dec_use_count,
-	parport_pc_fill_inode
+	parport_pc_fill_inode,
+
+	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,
 };
 
 /* --- Mode detection ------------------------------------- */
 
-
 /*
  * Checks for port existence, all ports support SPP MODE
  */
@@ -339,22 +994,23 @@
 	 * that does not even respond to SPP cycles if an EPP
 	 * timeout is pending
 	 */
-	parport_pc_epp_clear_timeout(pb);
+	clear_epp_timeout(pb);
 
 	/* Do a simple read-write test to make sure the port exists. */
 	w = 0xc;
-	parport_pc_write_control(pb, w);
+	outb (w, CONTROL (pb));
 
-	/* Can we read from the control register?  Some ports don't
-	 * allow reads, so read_control just returns a software
-	 * copy. Some ports _do_ allow reads, so bypass the software
-	 * copy here.  In addition, some bits aren't writable. */
+	/* Is there a control register that we can read from?  Some
+	 * ports don't allow reads, so read_control just returns a
+	 * software copy. Some ports _do_ allow reads, so bypass the
+	 * software copy here.  In addition, some bits aren't
+	 * writable. */
 	r = inb (CONTROL (pb));
 	if ((r & 0xf) == w) {
 		w = 0xe;
-		parport_pc_write_control (pb, w);
-		r = inb (CONTROL(pb));
-		parport_pc_write_control (pb, 0xc);
+		outb (w, CONTROL (pb));
+		r = inb (CONTROL (pb));
+		outb (0xc, CONTROL (pb));
 		if ((r & 0xf) == w)
 			return PARPORT_MODE_PCSPP;
 	}
@@ -379,20 +1035,20 @@
 	}
 
 	if (user_specified)
-		/* Didn't work with 0xaa, but the user is convinced
-		 * this is the place. */
+		/* Didn't work, but the user is convinced this is the
+		 * place. */
 		printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
 			pb->base, w, r);
 
 	/* It's possible that we can't read the control register or
-	   the data register.  In that case just believe the user. */
+	 * the data register.  In that case just believe the user. */
 	if (user_specified)
 		return PARPORT_MODE_PCSPP;
 
 	return 0;
 }
 
-/* Check for ECP
+/* Check for ECR
  *
  * Old style XT ports alias io ports every 0x400, hence accessing ECR
  * on these cards actually accesses the CTR.
@@ -401,82 +1057,225 @@
  * regardless of what is written here if the card does NOT support
  * ECP.
  *
- * We will write 0x2c to ECR and 0xcc to CTR since both of these
- * values are "safe" on the CTR since bits 6-7 of CTR are unused.
+ * We first check to see if ECR is the same as CTR.  If not, the low
+ * 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)
 {
-	unsigned char r;
+	struct parport_pc_private *priv = pb->private_data;
+	unsigned char r = 0xc;
 
-	parport_pc_write_control (pb, 0xc);
-	r = parport_pc_read_control(pb);	
-	if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
-		parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
+	priv->ecr = 0;
+	outb (r, CONTROL (pb));
+	if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
+		outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
 
-		r = parport_pc_read_control(pb);	
-		if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2))
+		r = inb (CONTROL (pb));
+		if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
 			goto no_reg; /* Sure that no ECR register exists */
 	}
 	
-	if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1)
+	if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
 		goto no_reg;
 
-	parport_pc_write_econtrol(pb, 0x34);
-	if (parport_pc_read_econtrol(pb) != 0x35)
+	outb (0x34, ECONTROL (pb));
+	if (inb (ECONTROL (pb)) != 0x35)
 		goto no_reg;
 
-	parport_pc_write_control(pb, 0xc);
-
-	/* Go to mode 000; SPP, reset FIFO */
-	parport_pc_frob_econtrol (pb, 0xe0, 0x00);
+	priv->ecr = 1;
+	outb (0xc, CONTROL (pb));
 	
-	return PARPORT_MODE_PCECR;
+	/* Go to mode 000 */
+	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+
+	return 1;
 
  no_reg:
-	parport_pc_write_control (pb, 0xc);
-	return 0;
+	outb (0xc, CONTROL (pb));
+	return 0; 
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines.  In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero.  So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present. 
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal.  Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic. 
+ */
+
+static int __init parport_PS2_supported(struct parport *pb)
+{
+	int ok = 0;
+  
+	clear_epp_timeout(pb);
+
+	/* try to tri-state the buffer */
+	parport_pc_data_reverse (pb);
+	
+	parport_pc_write_data(pb, 0x55);
+	if (parport_pc_read_data(pb) != 0x55) ok++;
+
+	parport_pc_write_data(pb, 0xaa);
+	if (parport_pc_read_data(pb) != 0xaa) ok++;
+
+	/* cancel input mode */
+	parport_pc_data_forward (pb);
+
+	if (ok)
+		pb->modes |= PARPORT_MODE_TRISTATE;
+	else {
+		struct parport_pc_private *priv = pb->private_data;
+		priv->ctr_writable &= ~0x20;
+	}
+
+	return ok;
 }
 
 static int __init parport_ECP_supported(struct parport *pb)
 {
 	int i;
-	unsigned char oecr;
-	
+	int config;
+	int pword;
+	struct parport_pc_private *priv = pb->private_data;
+
 	/* If there is no ECR, we have no hope of supporting ECP. */
-	if (!(pb->modes & PARPORT_MODE_PCECR))
+	if (!priv->ecr)
 		return 0;
 
-	oecr = parport_pc_read_econtrol(pb);
+	/* Find out FIFO depth */
+	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+	outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
+	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
+		outb (0xaa, FIFO (pb));
+
 	/*
 	 * Using LGS chipset it uses ECR register, but
 	 * it doesn't support ECP or FIFO MODE
 	 */
+	if (i == 1024) {
+		outb (ECR_SPP << 5, ECONTROL (pb));
+		return 0;
+	}
+
+	priv->fifo_depth = i;
+	printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
+
+	/* Find out writeIntrThreshold */
+	frob_econtrol (pb, 1<<2, 1<<2);
+	frob_econtrol (pb, 1<<2, 0);
+	for (i = 1; i <= priv->fifo_depth; i++) {
+		inb (FIFO (pb));
+		udelay (50);
+		if (inb (ECONTROL (pb)) & (1<<2))
+			break;
+	}
+
+	if (i <= priv->fifo_depth)
+		printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
+			pb->base, i);
+	else
+		/* Number of bytes we know we can write if we get an
+                   interrupt. */
+		i = 0;
+
+	priv->writeIntrThreshold = i;
+
+	/* Find out readIntrThreshold */
+	frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
+	parport_pc_data_reverse (pb);
+	frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
+	frob_econtrol (pb, 1<<2, 1<<2);
+	frob_econtrol (pb, 1<<2, 0);
+	for (i = 1; i <= priv->fifo_depth; i++) {
+		outb (0xaa, FIFO (pb));
+		if (inb (ECONTROL (pb)) & (1<<2))
+			break;
+	}
+
+	if (i <= priv->fifo_depth)
+		printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
+			pb->base, i);
+	else
+		/* Number of bytes we can read if we get an interrupt. */
+		i = 0;
+
+	priv->readIntrThreshold = i;
+
+	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+	outb (0xf4, ECONTROL (pb)); /* Configuration mode */
+	config = inb (FIFO (pb));
+	pword = (config >> 4) & 0x7;
+	switch (pword) {
+	case 0:
+		pword = 2;
+		printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+			pb->base);
+		break;
+	case 2:
+		pword = 4;
+		printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+			pb->base);
+		break;
+	default:
+		printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
+			pb->base);
+		/* Assume 1 */
+	case 1:
+		pword = 1;
+	}
+	priv->pword = pword;
+	printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
+
+	config = inb (CONFIGB (pb));
+	printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
+		config & 0x80 ? "Level" : "Pulses");
+
+	if (!(config & 0x40)) {
+		printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
+		pb->irq = PARPORT_IRQ_NONE;
+	}
+
+	/* Go back to mode 000 */
+	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+	pb->modes |= PARPORT_MODE_ECP;
+
+	return 1;
+}
+
+static int __init parport_ECPPS2_supported(struct parport *pb)
+{
+	const struct parport_pc_private *priv = pb->private_data;
+	int result;
+	unsigned char oecr;
+
+	if (!priv->ecr)
+		return 0;
+
+	oecr = inb (ECONTROL (pb));
+	outb (ECR_PS2 << 5, ECONTROL (pb));
 	
-	parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */
-	for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++)
-		parport_pc_write_fifo(pb, 0xaa);
-
-	parport_pc_write_econtrol(pb, oecr);
-	return (i==1024)?0:PARPORT_MODE_PCECP;
+	result = parport_PS2_supported(pb);
+
+	outb (oecr, ECONTROL (pb));
+	return result;
 }
 
-/* EPP mode detection
- * Theory:
- *	Bit 0 of STR is the EPP timeout bit, this bit is 0
- *	when EPP is possible and is set high when an EPP timeout
- *	occurs (EPP uses the HALT line to stop the CPU while it does
- *	the byte transfer, an EPP timeout occurs if the attached
- *	device fails to respond after 10 micro seconds).
- *
- *	This bit is cleared by either reading it (National Semi)
- *	or writing a 1 to the bit (SMC, UMC, WinBond), others ???
- *	This bit is always high in non EPP modes.
- */
+/* EPP mode detection  */
+
 static int __init parport_EPP_supported(struct parport *pb)
 {
-	/* If EPP timeout bit clear then EPP available */
-	if (!parport_pc_epp_clear_timeout(pb))
-		return 0;  /* No way to clear timeout */
+	const struct parport_pc_private *priv = pb->private_data;
 
 	/*
 	 * Theory:
@@ -491,132 +1290,70 @@
 	 *	This bit is always high in non EPP modes.
 	 */
 
-	parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
-	parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
-	parport_pc_epp_clear_timeout(pb);
-	
-	parport_pc_read_epp(pb);
-	udelay(30);  /* Wait for possible EPP timeout */
-	
-	if (parport_pc_read_status(pb) & 0x01) {
-		parport_pc_epp_clear_timeout(pb);
-		return PARPORT_MODE_PCEPP;
-	}
-
-	/*
-	 * Theory:
-	 *     Write two values to the EPP address register and
-	 *     read them back. When the transfer times out, the state of
-	 *     the EPP register is undefined in some cases (EPP 1.9?) but
-	 *     in others (EPP 1.7, ECPEPP?) it is possible to read back
-	 *     its value.
-	 */
-	parport_pc_epp_clear_timeout(pb);
-	udelay(30); /* Wait for possible EPP timeout */
-
-	/* Previous test left outputs disabled. */
-	outb (0x55, EPPADDR (pb));
-
-	parport_pc_epp_clear_timeout(pb);
-	udelay(30); /* Wait for possible EPP timeout */
-
-	/* We must enable the outputs to be able to read the address
-           register. */
-	parport_pc_frob_control (pb, 0x20, 0x00);
-
-	if (inb (EPPADDR (pb)) == 0x55) {
-
-		/* wash ... */
-		parport_pc_frob_control (pb, 0x20, 0x20);
-		outb (0xaa, EPPADDR (pb));
-
-		parport_pc_epp_clear_timeout(pb);
-		udelay(30); /* Wait for possible EPP timeout */
-
-		/* ... and repeat */
-		parport_pc_frob_control (pb, 0x20, 0x00);
+	/* If EPP timeout bit clear then EPP available */
+	if (!clear_epp_timeout(pb))
+		return 0;  /* No way to clear timeout */
 
-		if (inb (EPPADDR (pb)) == 0xaa) {
-			parport_pc_epp_clear_timeout (pb);
-			return PARPORT_MODE_PCEPP;
+	/* Check for Intel bug. */
+	if (priv->ecr) {
+		unsigned char i;
+		for (i = 0x00; i < 0x80; i += 0x20) {
+			outb (i, ECONTROL (pb));
+			if (clear_epp_timeout (pb))
+				/* Phony EPP in ECP. */
+				return 0;
 		}
 	}
 
-	return 0;
+	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;
+
+	return 1;
 }
 
 static int __init parport_ECPEPP_supported(struct parport *pb)
 {
-	int mode;
+	struct parport_pc_private *priv = pb->private_data;
+	int result;
 	unsigned char oecr;
 
-	if (!(pb->modes & PARPORT_MODE_PCECR))
+	if (!priv->ecr)
 		return 0;
 
-	oecr = parport_pc_read_econtrol(pb);
+	oecr = inb (ECONTROL (pb));
 	/* Search for SMC style EPP+ECP mode */
-	parport_pc_write_econtrol(pb, 0x80);
+	outb (0x80, ECONTROL (pb));
 	
-	mode = parport_EPP_supported(pb);
+	result = parport_EPP_supported(pb);
 
-	parport_pc_write_econtrol(pb, oecr);
-	
-	return mode?PARPORT_MODE_PCECPEPP:0;
-}
-
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines.  In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero.  So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present. 
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal.  Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic. 
- */
+	outb (oecr, ECONTROL (pb));
 
-static int __init parport_PS2_supported(struct parport *pb)
-{
-	int ok = 0;
-	unsigned char octr = parport_pc_read_control(pb);
-  
-	parport_pc_epp_clear_timeout(pb);
-
-	parport_pc_write_control(pb, octr | 0x20);  /* try to tri-state the buffer */
-	
-	parport_pc_write_data(pb, 0x55);
-	if (parport_pc_read_data(pb) != 0x55) ok++;
-
-	parport_pc_write_data(pb, 0xaa);
-	if (parport_pc_read_data(pb) != 0xaa) ok++;
-	
-	parport_pc_write_control(pb, octr);          /* cancel input mode */
+	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;
+	}
 
-	return ok?PARPORT_MODE_PCPS2:0;
+	return result;
 }
 
-static int __init parport_ECPPS2_supported(struct parport *pb)
-{
-	int mode;
-	unsigned char oecr;
-
-	if (!(pb->modes & PARPORT_MODE_PCECR))
-		return 0;
+#else /* No IEEE 1284 support */
 
-	oecr = parport_pc_read_econtrol(pb);
-	parport_pc_write_econtrol(pb, 0x20);
-	
-	mode = parport_PS2_supported(pb);
+/* 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; }
 
-	parport_pc_write_econtrol(pb, oecr);
-	return mode?PARPORT_MODE_PCECPPS2:0;
-}
+#endif /* No IEEE 1284 support */
 
 /* --- IRQ detection -------------------------------------- */
 
@@ -624,17 +1361,17 @@
 static int __init programmable_irq_support(struct parport *pb)
 {
 	int irq, intrLine;
-	unsigned char oecr = parport_pc_read_econtrol(pb);
+	unsigned char oecr = inb (ECONTROL (pb));
 	static const int lookup[8] = {
 		PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
 	};
 
-	parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */
-	
-	intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07;
+	outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
+
+	intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
 	irq = lookup[intrLine];
 
-	parport_pc_write_econtrol(pb, oecr);
+	outb (oecr, ECONTROL (pb));
 	return irq;
 }
 
@@ -645,15 +1382,16 @@
 	sti();
 	irqs = probe_irq_on();
 		
-	parport_pc_write_econtrol(pb, 0x00);	/* Reset FIFO */
-	parport_pc_write_econtrol(pb, 0xd0);	/* TEST FIFO + nErrIntrEn */
-
-	/* If Full FIFO sure that WriteIntrThresold is generated */
-	for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) 
-		parport_pc_write_fifo(pb, 0xaa);
+	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+	outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
+	outb (ECR_TST << 5, ECONTROL (pb));
+
+	/* If Full FIFO sure that writeIntrThreshold is generated */
+	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
+		outb (0xaa, FIFO (pb));
 		
 	pb->irq = probe_irq_off(irqs);
-	parport_pc_write_econtrol(pb, 0x00);
+	outb (ECR_SPP << 5, ECONTROL (pb));
 
 	if (pb->irq <= 0)
 		pb->irq = PARPORT_IRQ_NONE;
@@ -671,22 +1409,21 @@
 	return PARPORT_IRQ_NONE;
 #else
 	int irqs;
-	unsigned char octr = parport_pc_read_control(pb);
 	unsigned char oecr;
 
 	if (pb->modes & PARPORT_MODE_PCECR)
-		oecr = parport_pc_read_econtrol(pb);
+		oecr = inb (ECONTROL (pb));
 
 	sti();
 	irqs = probe_irq_on();
 
 	if (pb->modes & PARPORT_MODE_PCECR)
-		parport_pc_frob_econtrol (pb, 0x10, 0x10);
+		frob_econtrol (pb, 0x10, 0x10);
 	
-	parport_pc_epp_clear_timeout(pb);
+	clear_epp_timeout(pb);
 	parport_pc_frob_control (pb, 0x20, 0x20);
 	parport_pc_frob_control (pb, 0x10, 0x10);
-	parport_pc_epp_clear_timeout(pb);
+	clear_epp_timeout(pb);
 
 	/* Device isn't expecting an EPP read
 	 * and generates an IRQ.
@@ -696,56 +1433,20 @@
 
 	pb->irq = probe_irq_off (irqs);
 	if (pb->modes & PARPORT_MODE_PCECR)
-		parport_pc_write_econtrol(pb, oecr);
-	parport_pc_write_control(pb, octr);
+		outb (oecr, ECONTROL (pb));
+	parport_pc_write_control(pb, 0xc);
 
 	if (pb->irq <= 0)
 		pb->irq = PARPORT_IRQ_NONE;
 
 	return pb->irq;
-#endif /* Advanced detection. */
+#endif /* Advanced detection */
 }
 
 static int __init irq_probe_SPP(struct parport *pb)
 {
-#ifndef ADVANCED_DETECT
 	/* Don't even try to do this. */
 	return PARPORT_IRQ_NONE;
-#else
-	int irqs;
-	unsigned char octr = parport_pc_read_control(pb);
-	unsigned char oecr;
-
-	if (pb->modes & PARPORT_MODE_PCECR)
-		oecr = parport_pc_read_econtrol(pb);
-	probe_irq_off(probe_irq_on());	/* Clear any interrupts */
-	irqs = probe_irq_on();
-
-	if (pb->modes & PARPORT_MODE_PCECR)
-		parport_pc_write_econtrol(pb, 0x10);
-
-	parport_pc_write_data(pb,0x00);
-	parport_pc_write_control(pb,0x00);
-	parport_pc_write_control(pb,0x0c);
-	udelay(5);
-	parport_pc_write_control(pb,0x0d);
-	udelay(5);
-	parport_pc_write_control(pb,0x0c);
-	udelay(25);
-	parport_pc_write_control(pb,0x08);
-	udelay(25);
-	parport_pc_write_control(pb,0x0c);
-	udelay(50);
-
-	pb->irq = probe_irq_off(irqs);
-	if (pb->irq <= 0)
-		pb->irq = PARPORT_IRQ_NONE;	/* No interrupt detected */
-	
-	if (pb->modes & PARPORT_MODE_PCECR)
-		parport_pc_write_econtrol(pb, oecr);
-	parport_pc_write_control(pb, octr);
-	return pb->irq;
-#endif /* Advanced detection. */
 }
 
 /* We will attempt to share interrupt requests since other devices
@@ -757,25 +1458,27 @@
  */
 static int __init parport_irq_probe(struct parport *pb)
 {
-	if (pb->modes & PARPORT_MODE_PCECR) {
+	const struct parport_pc_private *priv = pb->private_data;
+
+	if (priv->ecr) {
 		pb->irq = programmable_irq_support(pb);
 		if (pb->irq != PARPORT_IRQ_NONE)
 			goto out;
 	}
 
-	if (pb->modes & PARPORT_MODE_PCECP)
+	if (pb->modes & PARPORT_MODE_ECP)
 		pb->irq = irq_probe_ECP(pb);
 
-	if (pb->irq == PARPORT_IRQ_NONE && 
-	    (pb->modes & PARPORT_MODE_PCECPEPP))
+	if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
+	    (pb->modes & PARPORT_MODE_EPP))
 		pb->irq = irq_probe_EPP(pb);
 
-	parport_pc_epp_clear_timeout(pb);
+	clear_epp_timeout(pb);
 
-	if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP))
+	if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
 		pb->irq = irq_probe_EPP(pb);
 
-	parport_pc_epp_clear_timeout(pb);
+	clear_epp_timeout(pb);
 
 	if (pb->irq == PARPORT_IRQ_NONE)
 		pb->irq = irq_probe_SPP(pb);
@@ -784,6 +1487,33 @@
 	return pb->irq;
 }
 
+/* --- DMA detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_dma_support (struct parport *p)
+{
+	unsigned char oecr = inb (ECONTROL (p));
+	int dma;
+
+	frob_econtrol (p, 0xe0, ECR_CNF << 5);
+	
+	dma = inb (CONFIGB(p)) & 0x03;
+	if (!dma)
+		dma = PARPORT_DMA_NONE;
+
+	outb (oecr, ECONTROL (p));
+	return dma;
+}
+
+static int __init parport_dma_probe (struct parport *p)
+{
+	const struct parport_pc_private *priv = p->private_data;
+	if (priv->ecr)
+		p->dma = programmable_dma_support(p);
+
+	return p->dma;
+}
+
 /* --- Initialisation code -------------------------------- */
 
 static int __init probe_one_port(unsigned long int base,
@@ -801,6 +1531,10 @@
 		return 0;
 	}
 	priv->ctr = 0xc;
+	priv->ctr_writable = 0xff;
+	priv->ecr = 0;
+	priv->fifo_depth = 0;
+	priv->dma_buf = 0;
 	p->base = base;
 	p->base_hi = base_hi;
 	p->irq = irq;
@@ -808,39 +1542,41 @@
 	p->modes = PARPORT_MODE_PCSPP;
 	p->ops = &parport_pc_ops;
 	p->private_data = priv;
-	if (base_hi && !check_region (base_hi, 3)) {
-		p->modes |= parport_ECR_present (p);
-		p->modes |= parport_ECP_supported (p);
-		p->modes |= parport_ECPPS2_supported (p);
+	p->physport = p;
+	if (base_hi && !check_region(base_hi,3)) {
+		parport_ECR_present(p);
+		parport_ECP_supported(p);
+		parport_ECPPS2_supported(p);
 	}
-	if (p->base != 0x3bc) {
+	if (base != 0x3bc) {
 		if (!check_region(base+0x3, 5)) {
-			p->modes |= parport_EPP_supported (p);
-			p->modes |= parport_ECPEPP_supported (p);
+			parport_EPP_supported(p);
+			if (!(p->modes & PARPORT_MODE_EPP))
+				parport_ECPEPP_supported(p);
 		}
 	}
-	if (!parport_SPP_supported(p)) {
+	if (!parport_SPP_supported (p)) {
 		/* No port. */
 		kfree (priv);
 		return 0;
 	}
 
-	p->modes |= parport_PS2_supported(p);
+	parport_PS2_supported (p);
 
-	if (!(p = parport_register_port (base, PARPORT_IRQ_NONE,
-					 PARPORT_DMA_NONE, &parport_pc_ops))) {
+	if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+									PARPORT_DMA_NONE, &parport_pc_ops))) {
 		kfree (priv);
 		return 0;
 	}
 
 	p->base_hi = base_hi;
 	p->modes = tmp.modes;
-	p->size = (p->modes & PARPORT_MODE_PCEPP) ? 8 : 3;
+	p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
 	p->private_data = priv;
 
 	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
-	if (p->base_hi && (p->modes & PARPORT_MODE_PCECR))
-		printk (" (0x%lx)", p->base_hi);
+	if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
+		printk(" (0x%lx)", p->base_hi);
 	p->irq = irq;
 	p->dma = dma;
 	if (p->irq == PARPORT_IRQ_AUTO) {
@@ -852,33 +1588,54 @@
 		probedirq = p->irq;
 		p->irq = PARPORT_IRQ_NONE;
 	}
-	if (p->irq != PARPORT_IRQ_NONE)
+	if (p->irq != PARPORT_IRQ_NONE) {
 		printk(", irq %d", p->irq);
+
+		if (p->dma == PARPORT_DMA_AUTO) {
+			p->dma = PARPORT_DMA_NONE;
+			parport_dma_probe(p);
+		}
+	}
 	if (p->dma == PARPORT_DMA_AUTO)		
 		p->dma = PARPORT_DMA_NONE;
-	if (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;
+#ifdef CONFIG_PARPORT_1284
+		parport_pc_ops.ecp_write_data =
+			parport_pc_ecp_write_block_pio;
+#endif /* IEEE 1284 support */
+		if (p->dma != PARPORT_DMA_NONE)
+			p->modes |= PARPORT_MODE_DMA;
+		printk(", using FIFO");
+	}
+#endif /* Allowed to use FIFO/DMA */
+
 	printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}}
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
 	{
 		int f = 0;
-		printmode(SPP);
-		printmode(PS2);
+		printmode(PCSPP);
+		printmode(TRISTATE);
+		printmode(COMPAT)
 		printmode(EPP);
 		printmode(ECP);
-		printmode(ECPEPP);
-		printmode(ECPPS2);
+		printmode(DMA);
 	}
 #undef printmode
 	printk("]\n");
-#ifdef	CONFIG_PROC_FS
 	if (probedirq != PARPORT_IRQ_NONE) 
-		printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
-#endif
+		printk("%s: irq %d detected\n", p->name, probedirq);
 	parport_proc_register(p);
 
-	request_region (p->base, p->size, p->name);
-	if (p->modes & PARPORT_MODE_PCECR)
+	request_region (p->base, 3, p->name);
+	if (p->size > 3)
+		request_region (p->base + 3, p->size - 3, p->name);
+	if (p->modes & PARPORT_MODE_ECP)
 		request_region (p->base_hi, 3, p->name);
 
 	if (p->irq != PARPORT_IRQ_NONE) {
@@ -897,25 +1654,38 @@
 					"resorting to PIO operation\n",
 					p->name, p->dma);
 				p->dma = PARPORT_DMA_NONE;
+			} else {
+				priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
+				if (! priv->dma_buf) {
+					printk (KERN_WARNING "%s: "
+						"cannot get buffer for DMA, "
+						"resorting to PIO operation\n",
+						p->name);
+					free_dma(p->dma);
+					p->dma = PARPORT_DMA_NONE;
+				}
 			}
 		}
 	}
 
-	/* Done probing.  Now put the port into a sensible start-up state. */
-	if (p->modes & PARPORT_MODE_PCECR)
+	/* Done probing.  Now put the port into a sensible start-up state.
+	 * SELECT | INIT also puts IEEE1284-compliant devices into
+	 * compatibility mode. */
+	if (p->modes & PARPORT_MODE_ECP)
 		/*
 		 * Put the ECP detected port in PS2 mode.
 		 */
-		parport_pc_write_econtrol(p, 0x24);
+		outb (0x24, ECONTROL (p));
+
 	parport_pc_write_data(p, 0);
-	parport_pc_write_control(p, 0x8);
+	parport_pc_data_forward (p);
+	parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
 	udelay (50);
-	parport_pc_write_control(p, 0xc);
+	parport_pc_write_control(p,
+				 PARPORT_CONTROL_SELECT
+				 | PARPORT_CONTROL_INIT);
 	udelay (50);
 
-	if (parport_probe_hook)
-		(*parport_probe_hook)(p);
-
 	/* Now that we've told the sharing engine about the port, and
 	   found out its characteristics, let the high-level drivers
 	   know about it. */
@@ -953,11 +1723,8 @@
 #define PCI_DEVICE_ID_LAVA_PARALLEL     0x8000
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A   0x8001 /* The Lava Dual Parallel is */
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B   0x8002 /* two PCI devices on a card */
-#endif /* IDs not defined */
+#endif
 
-	int count = 0;
-#ifdef CONFIG_PCI
-	int i;
 	struct {
 		unsigned int vendor;
 		unsigned int device;
@@ -1014,6 +1781,9 @@
 		{ 0, }
 	};
 
+	int count = 0;
+	int i;
+
 	if (!pci_present ())
 		return 0;
 
@@ -1036,7 +1806,6 @@
 			}
 		}
 	}
-#endif /* CONFIG_PCI */
 
 	return count;
 }
@@ -1070,17 +1839,9 @@
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
-
-MODULE_PARM_DESC(io, "base address");
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-
-MODULE_PARM_DESC(io_hi, "base address for ECR");
 MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-
-MODULE_PARM_DESC(irq, "irq line to use (or 'auto' or 'none')");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-
-MODULE_PARM_DESC(dma, "dma channel to use (or 'auto' or 'none')");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 
 int init_module(void)
@@ -1120,15 +1881,20 @@
 	struct parport *p = parport_enumerate(), *tmp;
 	while (p) {
 		tmp = p->next;
-		if (p->modes & PARPORT_MODE_PCSPP) {
+		if (p->modes & PARPORT_MODE_PCSPP) { 
+			struct parport_pc_private *priv = p->private_data;
 			if (p->dma != PARPORT_DMA_NONE)
-				free_dma (p->dma);
+				free_dma(p->dma);
 			if (p->irq != PARPORT_IRQ_NONE)
-				free_irq (p->irq, p);
-			release_region (p->base, p->size);
-			if (p->modes & PARPORT_MODE_PCECP)
-				release_region (p->base_hi, 3);
+				free_irq(p->irq, p);
+			release_region(p->base, 3);
+			if (p->size > 3);
+				release_region(p->base + 3, p->size - 3);
+			if (p->modes & PARPORT_MODE_ECP)
+				release_region(p->base_hi, 3);
 			parport_proc_unregister(p);
+			if (priv->dma_buf)
+				free_page((unsigned long) priv->dma_buf);
 			kfree (p->private_data);
 			parport_unregister_port(p);
 		}
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_probe.c linux/drivers/misc/parport_probe.c
--- v2.3.9/linux/drivers/misc/parport_probe.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_probe.c	Sun Jul  4 09:53:12 1999
@@ -0,0 +1,212 @@
+/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
+ * Parallel port device probing code
+ *
+ * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
+ *             Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+
+static struct {
+	char *token;
+	char *descr;
+} classes[] = {
+	{ "",            "Legacy device" },
+	{ "PRINTER",     "Printer" },
+	{ "MODEM",       "Modem" },
+	{ "NET",         "Network device" },
+	{ "HDC",       	 "Hard disk" },
+	{ "PCMCIA",      "PCMCIA" },
+	{ "MEDIA",       "Multimedia device" },
+	{ "FDC",         "Floppy disk" },
+	{ "PORTS",       "Ports" },
+	{ "SCANNER",     "Scanner" },
+	{ "DIGICAM",     "Digital camera" },
+	{ "",            "Unknown device" },
+	{ "",            "Unspecified" },
+	{ "SCSIADAPTER", "SCSI adapter" },
+	{ NULL,          NULL }
+};
+
+static void pretty_print(struct parport *port, int device)
+{
+	struct parport_device_info *info = &port->probe_info[device + 1];
+
+	printk(KERN_INFO "%s", port->name);
+
+	if (device >= 0)
+		printk (" (addr %d)", device);
+
+	printk (": %s", classes[info->class].descr);
+	if (info->class)
+		printk(", %s %s", info->mfr, info->model);
+
+	printk("\n");
+}
+
+static char *strdup(char *str)
+{
+	int n = strlen(str)+1;
+	char *s = kmalloc(n, GFP_KERNEL);
+	if (!s) return NULL;
+	return strcpy(s, str);
+}
+
+static void parse_data(struct parport *port, int device, char *str)
+{
+	char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
+	char *p = txt, *q;
+	int guessed_class = PARPORT_CLASS_UNSPEC;
+	struct parport_device_info *info = &port->probe_info[device + 1];
+
+	if (!txt) {
+		printk("%s probe: memory squeeze\n", port->name);
+		return;
+	}
+	strcpy(txt, str);
+	while (p) {
+		char *sep;
+		q = strchr(p, ';');
+		if (q) *q = 0;
+		sep = strchr(p, ':');
+		if (sep) {
+			char *u = p;
+			*(sep++) = 0;
+			while (*u) {
+				*u = toupper(*u);
+				u++;
+			}
+			if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
+				if (info->mfr)
+					kfree (info->mfr);
+				info->mfr = strdup(sep);
+			} else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
+				if (info->model)
+					kfree (info->model);
+				info->model = strdup(sep);
+			} else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
+				int i;
+				if (info->class_name)
+					kfree (info->class_name);
+				info->class_name = strdup(sep);
+				for (u = sep; *u; u++)
+					*u = toupper(*u);
+				for (i = 0; classes[i].token; i++) {
+					if (!strcmp(classes[i].token, sep)) {
+						info->class = i;
+						goto rock_on;
+					}
+				}
+				printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
+				info->class = PARPORT_CLASS_OTHER;
+			} else if (!strcmp(p, "CMD") ||
+				   !strcmp(p, "COMMAND SET")) {
+				if (info->cmdset)
+					kfree (info->cmdset);
+				info->cmdset = strdup(sep);
+				/* if it speaks printer language, it's
+				   probably a printer */
+				if (strstr(sep, "PJL") || strstr(sep, "PCL"))
+					guessed_class = PARPORT_CLASS_PRINTER;
+			} else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
+				if (info->description)
+					kfree (info->description);
+				info->description = strdup(sep);
+			}
+		}
+	rock_on:
+		if (q) p = q+1; else p=NULL;
+	}
+
+	/* If the device didn't tell us its class, maybe we have managed to
+	   guess one from the things it did say. */
+	if (info->class == PARPORT_CLASS_UNSPEC)
+		info->class = guessed_class;
+
+	pretty_print (port, device);
+
+	kfree(txt);
+}
+
+/* Get Std 1284 Device ID. */
+ssize_t parport_device_id (int devnum, char *buffer, size_t len)
+{
+	ssize_t retval = -ENXIO;
+	struct pardevice *dev = parport_open (devnum, "Device ID probe",
+					      NULL, NULL, NULL, 0, NULL);
+	if (!dev)
+		return -ENXIO;
+
+	parport_claim_or_block (dev);
+
+	/* Negotiate to compatibility mode, and then to device ID mode.
+	 * (This is in case we are already in device ID mode.) */
+	parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+	retval = parport_negotiate (dev->port,
+				    IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
+
+	if (!retval) {
+		int idlen;
+		unsigned char length[2];
+		mm_segment_t oldfs = get_fs ();
+		set_fs (get_ds ());
+
+		/* First two bytes are MSB,LSB of inclusive length. */
+		retval = parport_read (dev->port, length, 2);
+
+		if (retval != 2) goto restore_fs;
+
+		idlen = (length[0] << 8) + length[1] - 2;
+		if (idlen < len)
+			len = idlen;
+		retval = parport_read (dev->port, buffer, len);
+
+		if (retval != len) {
+			printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
+				dev->port->name, retval, len);
+			goto restore_fs;
+		}
+
+		/* Some printer manufacturers mistakenly believe that
+                   the length field is supposed to be _exclusive_. */
+		/* In addition, there are broken devices out there
+                   that don't even finish off with a semi-colon. */
+		if (idlen == len && buffer[len - 1] != ';') {
+			ssize_t diff;
+			diff = parport_read (dev->port, buffer + len, 2);
+			retval += diff;
+
+			if (diff)
+				printk (KERN_DEBUG
+					"%s: device reported incorrect "
+					"length field (%d, should be %d)\n",
+					dev->port->name, idlen, retval);
+			else {
+				/* One semi-colon short of a device ID. */
+				buffer[len++] = ';';
+				buffer[len] = '\0';
+				printk (KERN_DEBUG "%s: faking semi-colon\n",
+					dev->port->name);
+
+				/* If we get here, I don't think we
+                                   need to worry about the possible
+                                   standard violation of having read
+                                   more than we were told to.  The
+                                   device is non-compliant anyhow. */
+			}
+		}
+
+	restore_fs:
+		set_fs (oldfs);
+		parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+	}
+	parport_release (dev);
+
+	if (retval > 0)
+		parse_data (dev->port, dev->daisy, buffer);
+
+	parport_close (dev);
+	return retval;
+}
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.3.9/linux/drivers/misc/parport_procfs.c	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/parport_procfs.c	Thu Jul  1 14:22:57 1999
@@ -62,7 +62,7 @@
 	return copy_to_user(result, buffer, len) ? -EFAULT : 0;
 }
 
-#if 0 && defined (CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
 static int do_autoprobe(ctl_table *table, int write, struct file *filp,
 			void *result, size_t *lenp)
 {
@@ -146,9 +146,11 @@
 #define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
 		int f = 0;
 		printmode(PCSPP);
-		printmode(PCPS2);
-		printmode(PCEPP);
-		printmode(PCECP);
+		printmode(TRISTATE);
+		printmode(COMPAT);
+		printmode(EPP);
+		printmode(ECP);
+		printmode(DMA);
 #undef printmode
 	}
 	buffer[len++] = '\n';
@@ -190,7 +192,7 @@
 		  NULL, 0, 0444, NULL,
 		  &do_hardware },
 		PARPORT_DEVICES_ROOT_DIR,
-#if 0 && defined(CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
 		{ DEV_PARPORT_AUTOPROBE, "autoprobe",
 		  NULL, 0, 0444, NULL,
 		  &do_autoprobe },
@@ -292,17 +294,11 @@
 	for (i = 0; i < 8; i++)
 		t->vars[i].extra1 = port;
 
-#if 0 /* Wait for IEEE 1284 support */
 	t->vars[0].data = &port->spintime;
-#endif
 	t->vars[2].child = t->device_dir;
 	
 	for (i = 0; i < 5; i++)
-#if 0
 		t->vars[3 + i].extra2 = &port->probe_info[i];
-#else
-		t->vars[3 + i].extra2 = &port->probe_info;
-#endif
 
 	t->port_dir[0].procname = port->name;
 	t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
@@ -348,7 +344,7 @@
 	t->port_dir[0].child = t->devices_root_dir;
 	t->devices_root_dir[0].child = t->device_dir;
 
-#if 0 && defined(CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
 
 	t->device_dir[0].ctl_name =
 		parport_device_num(port->number, port->muxport,
diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.3.9/linux/drivers/misc/parport_share.c	Mon Jun  7 14:49:23 1999
+++ linux/drivers/misc/parport_share.c	Sun Jul  4 10:14:13 1999
@@ -14,11 +14,8 @@
 #undef PARPORT_DEBUG_SHARING		/* undef for production */
 
 #include <linux/config.h>
-
 #include <linux/string.h>
-
 #include <linux/tasks.h>
-
 #include <linux/parport.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -31,18 +28,12 @@
 #include <asm/spinlock.h>
 #include <asm/irq.h>
 
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
 #undef PARPORT_PARANOID
 
 #define PARPORT_DEFAULT_TIMESLICE	(HZ/5)
 
 unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
-
-/* This doesn't do anything yet. */
-int parport_default_spintime;
+int parport_default_spintime =  DEFAULT_SPIN_TIME;
 
 static struct parport *portlist = NULL, *portlist_tail = NULL;
 spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
@@ -50,7 +41,7 @@
 static struct parport_driver *driver_chain = NULL;
 spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
 
-static void call_driver_chain (int attach, struct parport *port)
+static void call_driver_chain(int attach, struct parport *port)
 {
 	struct parport_driver *drv;
 
@@ -96,19 +87,9 @@
 	}
 }
 
-void (*parport_probe_hook)(struct parport *port) = NULL;
-
 /* Return a list of all the ports we know about. */
 struct parport *parport_enumerate(void)
 {
-#ifdef CONFIG_KMOD
-	if (portlist == NULL) {
-		request_module("parport_lowlevel");
-#ifdef CONFIG_PNP_PARPORT_MODULE
-		request_module("parport_probe");
-#endif /* CONFIG_PNP_PARPORT_MODULE */
-	}
-#endif /* CONFIG_KMOD */
 	return portlist;
 }
 
@@ -117,16 +98,9 @@
 {
 	struct parport *tmp;
 	int portnum;
+	int device;
 	char *name;
 
-	/* Check for a previously registered port.
-	   NOTE: we will ignore irq and dma if we find a previously
-	   registered device.  */
-	for (tmp = portlist; tmp; tmp = tmp->next) {
-		if (tmp->base == base)
-			return tmp;
-	}
-
 	tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
 	if (!tmp) {
 		printk(KERN_WARNING "parport: memory squeeze\n");
@@ -154,16 +128,22 @@
 	tmp->base = base;
 	tmp->irq = irq;
 	tmp->dma = dma;
+	tmp->muxport = tmp->daisy = tmp->muxsel = -1;
 	tmp->modes = 0;
  	tmp->next = NULL;
 	tmp->devices = tmp->cad = NULL;
 	tmp->flags = 0;
 	tmp->ops = ops;
-	tmp->number = portnum;
-	memset (&tmp->probe_info, 0, sizeof (struct parport_device_info));
+	tmp->portnum = tmp->number = portnum;
+	tmp->physport = tmp;
+	memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
 	tmp->cad_lock = RW_LOCK_UNLOCKED;
 	spin_lock_init(&tmp->waitlist_lock);
 	spin_lock_init(&tmp->pardevice_lock);
+	tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
+	tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
+	tmp->spintime = parport_default_spintime;
 
 	name = kmalloc(15, GFP_KERNEL);
 	if (!name) {
@@ -188,7 +168,10 @@
 		portlist = tmp;
 	spin_unlock(&parportlist_lock);
 
-	tmp->probe_info.class = PARPORT_CLASS_LEGACY;  /* assume the worst */
+	for (device = 0; device < 5; device++)
+		/* assume the worst */
+		tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
+
 	tmp->waithead = tmp->waittail = NULL;
 
 	return tmp;
@@ -196,6 +179,11 @@
 
 void parport_announce_port (struct parport *port)
 {
+#ifdef CONFIG_PARPORT_1284
+	/* Analyse the IEEE1284.3 topology of the port. */
+	parport_daisy_init (port);
+#endif
+
 	/* Let drivers know that a new port has arrived. */
 	call_driver_chain (1, port);
 }
@@ -203,10 +191,16 @@
 void parport_unregister_port(struct parport *port)
 {
 	struct parport *p;
+	int d;
 
 	/* Spread the word. */
 	call_driver_chain (0, port);
 
+#ifdef CONFIG_PARPORT_1284
+	/* Forget the IEEE1284.3 topology of the port. */
+	parport_daisy_fini (port);
+#endif
+
 	spin_lock(&parportlist_lock);
 	if (portlist == port) {
 		if ((portlist = port->next) == NULL)
@@ -222,16 +216,20 @@
 			     "%s not found in port list!\n", port->name);
 	}
 	spin_unlock(&parportlist_lock);
-	if (port->probe_info.class_name)
-		kfree (port->probe_info.class_name);
-	if (port->probe_info.mfr)
-		kfree (port->probe_info.mfr);
-	if (port->probe_info.model)
-		kfree (port->probe_info.model);
-	if (port->probe_info.cmdset)
-		kfree (port->probe_info.cmdset);
-	if (port->probe_info.description)
-		kfree (port->probe_info.description);
+
+	for (d = 0; d < 5; d++) {
+		if (port->probe_info[d].class_name)
+			kfree (port->probe_info[d].class_name);
+		if (port->probe_info[d].mfr)
+			kfree (port->probe_info[d].mfr);
+		if (port->probe_info[d].model)
+			kfree (port->probe_info[d].model);
+		if (port->probe_info[d].cmdset)
+			kfree (port->probe_info[d].cmdset);
+		if (port->probe_info[d].description)
+			kfree (port->probe_info[d].description);
+	}
+
 	kfree(port->name);
 	kfree(port);
 }
@@ -243,7 +241,7 @@
 {
 	struct pardevice *tmp;
 
-	if (port->flags & PARPORT_FLAG_EXCL) {
+	if (port->physport->flags & PARPORT_FLAG_EXCL) {
 		/* An exclusive device is registered. */
 		printk (KERN_DEBUG "%s: no more devices allowed\n",
 			port->name);
@@ -272,13 +270,14 @@
 
 	tmp->name = name;
 	tmp->port = port;
+	tmp->daisy = -1;
 	tmp->preempt = pf;
 	tmp->wakeup = kf;
 	tmp->private = handle;
 	tmp->flags = flags;
 	tmp->irq_func = irq_func;
-	port->ops->init_state(tmp->state);
 	tmp->waiting = 0;
+	tmp->timeout = 5 * HZ;
 
 	/* Chain this onto the list */
 	tmp->prev = NULL;
@@ -286,11 +285,11 @@
 	 * This function must not run from an irq handler so we don' t need
 	 * to clear irq on the local CPU. -arca
 	 */
-	spin_lock(&port->pardevice_lock);
+	spin_lock(&port->physport->pardevice_lock);
 
 	if (flags & PARPORT_DEV_EXCL) {
-		if (port->devices) {
-			spin_unlock (&port->pardevice_lock);
+		if (port->physport->devices) {
+			spin_unlock (&port->physport->pardevice_lock);
 			kfree (tmp->state);
 			kfree (tmp);
 			printk (KERN_DEBUG
@@ -301,11 +300,11 @@
 		port->flags |= PARPORT_FLAG_EXCL;
 	}
 
-	tmp->next = port->devices;
-	if (port->devices)
-		port->devices->prev = tmp;
-	port->devices = tmp;
-	spin_unlock(&port->pardevice_lock);
+	tmp->next = port->physport->devices;
+	if (port->physport->devices)
+		port->physport->devices->prev = tmp;
+	port->physport->devices = tmp;
+	spin_unlock(&port->physport->pardevice_lock);
 
 	inc_parport_count();
 	port->ops->inc_use_count();
@@ -314,6 +313,12 @@
 	tmp->timeslice = parport_default_timeslice;
 	tmp->waitnext = tmp->waitprev = NULL;
 
+	/*
+	 * This has to be run as last thing since init_state may need other
+	 * pardevice fields. -arca
+	 */
+	port->ops->init_state(tmp, tmp->state);
+	parport_device_proc_register(tmp);
 	return tmp;
 }
 
@@ -328,7 +333,9 @@
 	}
 #endif
 
-	port = dev->port;
+	parport_device_proc_unregister(dev);
+
+	port = dev->port->physport;
 
 	if (port->cad == dev) {
 		printk(KERN_DEBUG "%s: %s forgot to release port\n",
@@ -354,19 +361,17 @@
 
 	dec_parport_count();
 	port->ops->dec_use_count();
-
-	return;
 }
 
 int parport_claim(struct pardevice *dev)
 {
 	struct pardevice *oldcad;
-	struct parport *port = dev->port;
+	struct parport *port = dev->port->physport;
 	unsigned long flags;
 
 	if (port->cad == dev) {
 		printk(KERN_INFO "%s: %s already owner\n",
-			   dev->port->name,dev->name);
+		       dev->port->name,dev->name);
 		return 0;
 	}
 
@@ -407,24 +412,27 @@
 		dev->waitprev = dev->waitnext = NULL;
 	}
 
-	if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func)
-		/*
-		 * If there was an irq pending it should hopefully happen
-		 * before return from enable_irq(). -arca
-		 */
-		enable_irq(port->irq);
-
-	/*
-	 * Avoid running irq handlers if the pardevice doesn' t use it. -arca
-	 */
-	if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
-		disable_irq(port->irq);
-
 	/* Now we do the change of devices */
 	write_lock_irqsave(&port->cad_lock, flags);
 	port->cad = dev;
 	write_unlock_irqrestore(&port->cad_lock, flags);
 
+#ifdef CONFIG_PARPORT_1284
+	/* If it's a mux port, select it. */
+	if (dev->port->muxport >= 0) {
+		/* FIXME */
+		port->muxsel = dev->port->muxport;
+	}
+
+	/* If it's a daisy chain device, select it. */
+	if (dev->daisy >= 0) {
+		/* This could be lazier. */
+		if (!parport_daisy_select (port, dev->daisy,
+					   IEEE1284_MODE_COMPAT))
+			port->daisy = dev->daisy;
+	}
+#endif /* IEEE1284.3 support */
+
 	/* Restore control registers */
 	port->ops->restore_state(port, dev->state);
 	dev->time = jiffies;
@@ -487,8 +495,11 @@
 		}
 		restore_flags(flags);
 #ifdef PARPORT_DEBUG_SHARING
-		if (dev->port->cad != dev)
-			printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", dev->name, dev->port->cad?dev->port->cad->name:"nobody");
+		if (dev->port->physport->cad != dev)
+			printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
+			       "but %s owns port!\n", dev->name,
+			       dev->port->physport->cad ?
+			       dev->port->physport->cad->name:"nobody");
 #endif
 	}
 	dev->waiting = 0;
@@ -497,7 +508,7 @@
 
 void parport_release(struct pardevice *dev)
 {
-	struct parport *port = dev->port;
+	struct parport *port = dev->port->physport;
 	struct pardevice *pd;
 	unsigned long flags;
 
@@ -507,16 +518,24 @@
 		       "when not owner\n", port->name, dev->name);
 		return;
 	}
+
+#ifdef CONFIG_PARPORT_1284
+	/* If this is on a mux port, deselect it. */
+	if (dev->port->muxport >= 0) {
+		/* FIXME */
+		port->muxsel = -1;
+	}
+
+	/* If this is a daisy device, deselect it. */
+	if (dev->daisy >= 0) {
+		parport_daisy_deselect_all (port);
+		port->daisy = -1;
+	}
+#endif
+
 	write_lock_irqsave(&port->cad_lock, flags);
 	port->cad = NULL;
 	write_unlock_irqrestore(&port->cad_lock, flags);
-
-	/*
-	 * Reenable irq and so discard the eventually pending irq while
-	 * cad is NULL. -arca
-	 */
-	if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
-		enable_irq(port->irq);
 
 	/* Save control registers */
 	port->ops->save_state(port, dev->state);
diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.3.9/linux/drivers/net/3c501.c	Thu Dec 31 12:03:49 1998
+++ linux/drivers/net/3c501.c	Tue Jul  6 19:05:49 1999
@@ -210,7 +210,7 @@
 struct netdev_entry el1_drv = {"3c501", el1_probe1, EL1_IO_EXTENT, netcard_portlist};
 #else
 
-__initfunc(int el1_probe(struct device *dev))
+int __init el1_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -237,7 +237,7 @@
  *	The actual probe.
  */
 
-__initfunc(static int el1_probe1(struct device *dev, int ioaddr))
+static int __init el1_probe1(struct device *dev, int ioaddr)
 {
 	struct net_local *lp;
 	const char *mname;		/* Vendor name */
diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v2.3.9/linux/drivers/net/3c503.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/3c503.c	Tue Jul  6 19:05:49 1999
@@ -90,8 +90,8 @@
    If the ethercard isn't found there is an optional probe for
    ethercard jumpered to programmed-I/O mode.
    */
-__initfunc(int
-el2_probe(struct device *dev))
+int __init 
+el2_probe(struct device *dev)
 {
     int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
     int base_addr = dev->base_addr;
@@ -125,8 +125,8 @@
 #ifndef HAVE_DEVLIST
 /*  Try all of the locations that aren't obviously empty.  This touches
     a lot of locations, and is much riskier than the code above. */
-__initfunc(int
-el2_pio_probe(struct device *dev))
+int __init 
+el2_pio_probe(struct device *dev)
 {
     int i;
     int base_addr = dev ? dev->base_addr : 0;
@@ -151,8 +151,8 @@
 /* Probe for the Etherlink II card at I/O port base IOADDR,
    returning non-zero on success.  If found, set the station
    address and memory parameters in DEVICE. */
-__initfunc(int
-el2_probe1(struct device *dev, int ioaddr))
+int __init 
+el2_probe1(struct device *dev, int ioaddr)
 {
     int i, iobase_reg, membase_reg, saved_406, wordlength;
     static unsigned version_printed = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.3.9/linux/drivers/net/3c505.c	Thu Dec 17 09:03:57 1998
+++ linux/drivers/net/3c505.c	Tue Jul  6 19:05:49 1999
@@ -1339,7 +1339,7 @@
  * Called only by elp_autodetect
  ************************************************************/
 
-__initfunc(static int elp_sense(struct device *dev))
+static int __init elp_sense(struct device *dev)
 {
 	int timeout;
 	int addr = dev->base_addr;
@@ -1406,7 +1406,7 @@
  * Called only by eplus_probe
  *************************************************************/
 
-__initfunc(static int elp_autodetect(struct device *dev))
+static int __init elp_autodetect(struct device *dev)
 {
 	int idx = 0;
 
@@ -1450,7 +1450,7 @@
  * work at all if it was in a weird state).
  */
 
-__initfunc(int elplus_probe(struct device *dev))
+int __init elplus_probe(struct device *dev)
 {
 	elp_device *adapter;
 	int i, tries, tries1, timeout, okay;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.3.9/linux/drivers/net/3c507.c	Thu May  6 23:14:36 1999
+++ linux/drivers/net/3c507.c	Tue Jul  6 19:05:49 1999
@@ -305,7 +305,7 @@
 	device and return success.
 	*/
 
-__initfunc(int el16_probe(struct device *dev))
+int __init el16_probe(struct device *dev)
 {
 	int base_addr = dev ? dev->base_addr : 0;
 	int i;
@@ -326,7 +326,7 @@
 	return ENODEV;
 }
 
-__initfunc(int el16_probe1(struct device *dev, int ioaddr))
+int __init el16_probe1(struct device *dev, int ioaddr)
 {
 	static unsigned char init_ID_done = 0, version_printed = 0;
 	int i, irq, irqval;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.3.9/linux/drivers/net/3c523.c	Sat Apr 24 17:49:37 1999
+++ linux/drivers/net/3c523.c	Tue Jul  6 19:05:49 1999
@@ -319,7 +319,7 @@
  * Check to see if there's an 82586 out there.
  */
 
-__initfunc(static int check586(struct device *dev, unsigned long where, unsigned size))
+static int __init check586(struct device *dev, unsigned long where, unsigned size)
 {
 	struct priv *p = (struct priv *) dev->priv;
 	char *iscp_addrs[2];
@@ -422,7 +422,7 @@
 
 /*****************************************************************/
 
-__initfunc(int elmc_probe(struct device *dev))
+int __init elmc_probe(struct device *dev)
 {
 	static int slot = 0;
 	int base_addr = dev ? dev->base_addr : 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c527.c linux/drivers/net/3c527.c
--- v2.3.9/linux/drivers/net/3c527.c	Wed May 12 13:27:37 1999
+++ linux/drivers/net/3c527.c	Tue Jul  6 19:05:49 1999
@@ -147,7 +147,7 @@
  * (detachable devices only).
  */
 
-__initfunc(int mc32_probe(struct device *dev))
+int __init mc32_probe(struct device *dev)
 {
 	static int current_mca_slot = -1;
 	int i;
@@ -183,7 +183,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 mc32_probe1(struct device *dev, int slot))
+static int __init mc32_probe1(struct device *dev, int slot)
 {
 	static unsigned version_printed = 0;
 	int i;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.3.9/linux/drivers/net/82596.c	Thu Jan  7 08:46:59 1999
+++ linux/drivers/net/82596.c	Tue Jul  6 19:05:49 1999
@@ -878,7 +878,7 @@
 	printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
 }
 
-__initfunc(int i82596_probe(struct device *dev))
+int __init i82596_probe(struct device *dev)
 {
 	int i;
 	struct i596_private *lp;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.9/linux/drivers/net/Config.in	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/Config.in	Wed Jul  7 09:14:26 1999
@@ -2,6 +2,9 @@
 # Network device configuration
 #
 
+mainmenu_option next_comment
+comment 'ARCnet devices'
+
 tristate 'ARCnet support' CONFIG_ARCNET
 if [ "$CONFIG_ARCNET" != "n" ]; then
   bool '  Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
@@ -12,6 +15,8 @@
   dep_tristate '  ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
 fi
 
+endmenu
+
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -22,6 +27,10 @@
 #
 #	Ethernet
 #
+
+mainmenu_option next_comment
+comment 'Ethernet (10 or 100Mbit)'
+
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   if [ "$CONFIG_ARM" = "y" ]; then
@@ -82,18 +91,15 @@
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
       tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
-      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
   fi
   bool 'Other ISA cards' CONFIG_NET_ISA
   if [ "$CONFIG_NET_ISA" = "y" ]; then
-    tristate 'AT1700/1720 support' CONFIG_AT1700
+    tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
     tristate 'Cabletron E21xx support' CONFIG_E2100
     tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
     tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
     tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
-    fi
+    tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
     tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X
     tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
     tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
@@ -103,7 +109,7 @@
     fi
     tristate 'NE2000/NE1000 support' CONFIG_NE2000
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
+      tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
     fi
     bool 'SK_G16 support' CONFIG_SK_G16
   fi
@@ -115,6 +121,7 @@
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
 
@@ -145,6 +152,8 @@
   fi
 fi
 
+endmenu
+
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
   bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
@@ -153,25 +162,20 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
   if [ "$CONFIG_HIPPI" = "y" ]; then
-    bool 'CERN HIPPI PCI adapter support' CONFIG_CERN_HIPPI
-    bool 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
+    tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
     if [ "$CONFIG_ROADRUNNER" != "n" ]; then
       bool '  Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
     fi
   fi
 fi
 
-tristate 'Frame relay DLCI support' CONFIG_DLCI
-if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
-  int '  Max open DLCI' CONFIG_DLCI_COUNT 24
-  int '  Max DLCI per device' CONFIG_DLCI_MAX 8
-  dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
-fi
-
 #
 # AppleTalk
 #
+
 if [ "$CONFIG_ATALK" != "n" ]; then
+  mainmenu_option next_comment
+  comment 'Appletalk devices'
   dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
   dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
   if [ "$CONFIG_COPS" != "n" ]; then
@@ -183,6 +187,7 @@
      bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
      bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
   fi
+  endmenu
 fi
 
 if [ ! "$CONFIG_PARPORT" = "n" ]; then
@@ -203,23 +208,38 @@
 
 bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" = "y" ]; then
-  tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
+  dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
   tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+  tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
+
 fi
 
+mainmenu_option next_comment
+comment 'Token ring devices'
+
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" = "y" ]; then
   tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
 #  tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS
+  tristate 'IBM Olympic chipset PCI adapter support' CONFIG_IBMOL
   tristate 'SysKonnect adapter support' CONFIG_SKTR
 fi
 
+endmenu
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
   tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
 fi
+
 #
 # WAN drivers support
 #
+
+mainmenu_option next_comment
+comment 'Wan interfaces'
+
+
 # There is no way to detect a comtrol sv11 - force it modular for now.
 #
 dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
@@ -227,8 +247,22 @@
 # The COSA/SRP driver has not been tested as non-modular yet.
 #
 dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m
-tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
 #
+# There is no way to detect a Sealevel board. Force it modular
+#
+dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
+
+tristate 'Frame relay DLCI support' CONFIG_DLCI
+if [ "$CONFIG_DLCI" != "n" ]; then
+  int '  Max open DLCI' CONFIG_DLCI_COUNT 24
+  int '  Max DLCI per device' CONFIG_DLCI_MAX 8
+  dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+fi
+
+#
+#	Wan router core.
+#
+
 if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
   bool 'WAN drivers' CONFIG_WAN_DRIVERS
   if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
@@ -247,6 +281,9 @@
     fi
   fi
 fi
+
+endmenu
+
 #
 # X.25 network drivers
 #
diff -u --recursive --new-file v2.3.9/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.9/linux/drivers/net/Makefile	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/Makefile	Tue Jul  6 19:16:55 1999
@@ -67,6 +67,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_IBMOL),y)
+L_OBJS += olympic.o
+else
+  ifeq ($(CONFIG_IBMOL),m)
+  M_OBJS += olympic.o
+  endif
+endif
+
 ifeq ($(CONFIG_SKTR),y)
 L_OBJS += sktr.o
 else
@@ -422,6 +430,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SUNBMAC),y)
+L_OBJS += sunbmac.o
+else
+  ifeq ($(CONFIG_SUNBMAC),m)
+  M_OBJS += sunbmac.o
+  endif
+endif
+
 ifeq ($(CONFIG_MYRI_SBUS),y)
 L_OBJS += myri_sbus.o
 else
@@ -566,6 +582,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_ARLAN),y)
+LX_OBJS += arlan.o arlan-proc.o
+else
+  ifeq ($(CONFIG_ARLAN),m)
+  MX_OBJS += arlan.o arlan-proc.o
+  endif
+endif
+
 ifeq ($(CONFIG_TLAN),y)
 L_OBJS += tlan.o
 else
@@ -764,6 +788,19 @@
   endif
 endif
 
+ifeq ($(CONFIG_SEALEVEL_4021),y)
+L_OBJS += sealevel.o
+CONFIG_85230_BUILTIN = y
+CONFIG_SYNCPPP_BUILTIN = y
+else
+  ifeq ($(CONFIG_SEALEVEL_4021),m)
+  CONFIG_85230_MODULE = y
+  CONFIG_SYNCPPP_MODULE = y
+  M_OBJS += sealevel.o
+  endif
+endif
+
+
 ifeq ($(CONFIG_COSA),y)
 L_OBJS += cosa.o
 CONFIG_SYNCPPP_BUILTIN = y
@@ -1061,15 +1098,6 @@
   L_OBJS += cycx_main.o
   ifeq ($(CONFIG_CYCLOMX_X25),y)
     L_OBJS += cycx_x25.o
-  endif
-endif
-
-ifeq ($(CONFIG_CYCLADES_SYNC),m)
-  MX_OBJS += cycx_drv.o
-  M_OBJS += cyclomx.o
-  CYCLOMX_OBJS = cycx_main.o
-  ifeq ($(CONFIG_CYCLOMX_X25),y)
-    CYCLOMX_OBJS += cycx_x25.o
   endif
 endif
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.9/linux/drivers/net/Space.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/Space.c	Tue Jul  6 19:05:49 1999
@@ -67,6 +67,7 @@
 extern int de4x5_probe(struct device *);
 extern int el1_probe(struct device *);
 extern int wavelan_probe(struct device *);
+extern int arlan_probe(struct device *);
 extern int el16_probe(struct device *);
 extern int elmc_probe(struct device *);
 extern int skmca_probe(struct device *);
@@ -147,7 +148,7 @@
  * autoprobe (i.e. a probe that fails to find a card when autoprobing
  * will not be asked to autoprobe again).  It exits when a card is found.
  */
-__initfunc(static int probe_list(struct device *dev, struct devprobe *plist))
+static int __init probe_list(struct device *dev, struct devprobe *plist)
 {
 	struct devprobe *p = plist;
 	unsigned long base_addr = dev->base_addr;
@@ -359,6 +360,9 @@
 #ifdef CONFIG_WAVELAN		/* WaveLAN */
 	{wavelan_probe, 0},
 #endif
+#ifdef CONFIG_ARLAN		/* Aironet */
+	{arlan_probe, 0},
+#endif
 #ifdef CONFIG_EL16		/* 3c507 */
 	{el16_probe, 0},
 #endif
@@ -474,7 +478,7 @@
  * Unified ethernet device probe, segmented per architecture and
  * per bus interface.
  */
-__initfunc(static int ethif_probe(struct device *dev))
+static int __init ethif_probe(struct device *dev)
 {
 	unsigned long base_addr = dev->base_addr;
 
@@ -522,7 +526,7 @@
 }
 
 #ifdef CONFIG_FDDI
-__initfunc(static int fddiif_probe(struct device *dev))
+static int __init fddiif_probe(struct device *dev)
 {
     unsigned long base_addr = dev->base_addr;
 
@@ -719,6 +723,7 @@
 #ifdef CONFIG_TR
 /* Token-ring device probe */
 extern int ibmtr_probe(struct device *);
+extern int olympic_probe(struct device *);
 
 static int
 trif_probe(struct device *dev)
@@ -726,6 +731,9 @@
     if (1
 #ifdef CONFIG_IBMTR
 	&& ibmtr_probe(dev)
+#endif
+#ifdef CONFIG_IBMOL
+	&& olympic_probe(dev)
 #endif
 #ifdef CONFIG_SKTR
 	&& sktr_probe(dev)
diff -u --recursive --new-file v2.3.9/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.3.9/linux/drivers/net/a2065.c	Sun Mar 21 07:22:00 1999
+++ linux/drivers/net/a2065.c	Tue Jul  6 19:05:49 1999
@@ -739,8 +739,7 @@
 	mark_bh(NET_BH);
 }
 
-
-__initfunc(int a2065_probe(struct device *dev))
+int __init a2065_probe(struct device *dev)
 {
 	unsigned int key, is_cbm;
 	const struct ConfigDev *cd;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v2.3.9/linux/drivers/net/ac3200.c	Thu Dec 17 09:03:57 1998
+++ linux/drivers/net/ac3200.c	Tue Jul  6 19:05:49 1999
@@ -95,7 +95,7 @@
 	or the unique value in the station address PROM.
 	*/
 
-__initfunc(int ac3200_probe(struct device *dev))
+int __init ac3200_probe(struct device *dev)
 {
 	unsigned short ioaddr = dev->base_addr;
 
@@ -117,7 +117,7 @@
 	return ENODEV;
 }
 
-__initfunc(static int ac_probe1(int ioaddr, struct device *dev))
+static int __init ac_probe1(int ioaddr, struct device *dev)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.3.9/linux/drivers/net/acenic.c	Mon Mar 22 08:08:12 1999
+++ linux/drivers/net/acenic.c	Tue Jul  6 19:05:49 1999
@@ -177,7 +177,7 @@
 
 static int probed __initdata = 0;
 
-__initfunc(int acenic_probe (struct device *dev))
+int __init acenic_probe (struct device *dev)
 {
 	int boards_found = 0;
 	int version_disp;
@@ -423,7 +423,7 @@
 }
 
 
-__initfunc(static int ace_init(struct device *dev, int board_idx))
+static int __init ace_init(struct device *dev, int board_idx)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
@@ -1574,7 +1574,7 @@
 }
 
 
-__initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size))
+void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)
 {
 	unsigned long tdest;
 	u32 *wsrc;
@@ -1609,7 +1609,7 @@
 }
 
 
-__initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size))
+void __init ace_clear(struct ace_regs *regs, u32 dest, int size)
 {
 	unsigned long tdest;
 	short tsize = 0, i;
@@ -1642,7 +1642,7 @@
  * This operation requires the NIC to be halted and is performed with
  * interrupts disabled and with the spinlock hold.
  */
-__initfunc(int ace_load_firmware(struct device *dev))
+int __init ace_load_firmware(struct device *dev)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/apne.c linux/drivers/net/apne.c
--- v2.3.9/linux/drivers/net/apne.c	Thu Dec 17 09:07:46 1998
+++ linux/drivers/net/apne.c	Tue Jul  6 19:05:49 1999
@@ -121,7 +121,7 @@
 
 static int apne_owned = 0;	/* signal if card already owned */
 
-__initfunc(int apne_probe(struct device *dev))
+int __init apne_probe(struct device *dev)
 {
 #ifndef MANUAL_CONFIG
 	char tuple[8];
@@ -161,8 +161,7 @@
 
 }
 
-
-__initfunc(static int apne_probe1(struct device *dev, int ioaddr))
+static int __init apne_probe1(struct device *dev, int ioaddr)
 {
     int i;
     unsigned char SA_prom[32];
diff -u --recursive --new-file v2.3.9/linux/drivers/net/arc-rimi.c linux/drivers/net/arc-rimi.c
--- v2.3.9/linux/drivers/net/arc-rimi.c	Mon Sep 14 11:32:22 1998
+++ linux/drivers/net/arc-rimi.c	Tue Jul  6 19:05:49 1999
@@ -100,7 +100,7 @@
 MODULE_PARM(device, "s");
 MODULE_PARM (node, "i");
 #else
-__initfunc(void arcrimi_setup (char *str, int *ints));
+void __init arcrimi_setup (char *str, int *ints);
 extern struct device arcnet_devs[];
 extern char arcnet_dev_names[][10];
 extern int arcnet_num_devs;
@@ -140,7 +140,7 @@
  * them.  In fact, we can't even get their node ID automatically.  So, we
  * need to be passed a specific shmem address, IRQ, and node ID.
  */
-__initfunc(int arcrimi_probe(struct device *dev))
+int __init arcrimi_probe(struct device *dev)
 {
   BUGLVL(D_NORMAL) printk(version);
   BUGMSG(D_NORMAL,"Given: node %02Xh, shmem %lXh, irq %d\n",
@@ -167,7 +167,7 @@
 /* Set up the struct device associated with this card.  Called after
  * probing succeeds.
  */
-__initfunc(int arcrimi_found(struct device *dev,int node,int airq, u_long shmem))
+int __init arcrimi_found(struct device *dev,int node,int airq, u_long shmem)
 {
   struct arcnet_local *lp;
   u_long first_mirror,last_mirror;
@@ -797,7 +797,7 @@
 
 #else
 
-__initfunc(void arcrimi_setup (char *str, int *ints))
+void __init arcrimi_setup (char *str, int *ints)
 {
   struct device *dev;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.3.9/linux/drivers/net/arcnet.c	Tue May 25 13:06:34 1999
+++ linux/drivers/net/arcnet.c	Tue Jul  6 19:05:49 1999
@@ -471,9 +471,16 @@
 
 #ifdef CONFIG_ARCNET_1051
   /* Initialize the RFC1051-encap protocol driver */
-  lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
+  lp->sdev=(struct device *)kmalloc(sizeof(struct device)+10,GFP_KERNEL);
+  if(lp->sdev = NULL)
+  {
+  	if(lp->edev)
+  		kfree(lp->edev);
+  	lp->edev=NULL;
+  	return -ENOMEM;
+  }
   memcpy(lp->sdev,dev,sizeof(struct device));
-  lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL);
+  lp->sdev->name=(char *)(lp+1);
   sprintf(lp->sdev->name,"%ss",dev->name);
   lp->sdev->init=arcnetS_init;
   register_netdevice(lp->sdev);
@@ -562,7 +569,6 @@
   /* free the RFC1051-encap protocol device */
   lp->sdev->priv=NULL;
   unregister_netdevice(lp->sdev);
-  kfree(lp->sdev->name);
   kfree(lp->sdev);
   lp->sdev=NULL;
 #endif
@@ -1991,7 +1997,7 @@
 int arcnet_num_devs=0;
 char arcnet_dev_names[MAX_ARCNET_DEVS][10];
 
-__initfunc(void arcnet_init(void))
+void __init arcnet_init(void)
 {
   int c;
 
@@ -2041,7 +2047,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-__initfunc(static int init_module(void))
+static int __init init_module(void)
 #endif
 {
 #ifdef ALPHA_WARNING
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v2.3.9/linux/drivers/net/ariadne.c	Thu Feb 25 10:02:13 1999
+++ linux/drivers/net/ariadne.c	Tue Jul  6 19:05:49 1999
@@ -146,7 +146,7 @@
 }
 
 
-__initfunc(int ariadne_probe(struct device *dev))
+int __init ariadne_probe(struct device *dev)
 {
     unsigned int key;
     const struct ConfigDev *cd;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c
--- v2.3.9/linux/drivers/net/ariadne2.c	Thu Jan  7 08:41:54 1999
+++ linux/drivers/net/ariadne2.c	Tue Jul  6 19:05:49 1999
@@ -81,8 +81,7 @@
 				  const unsigned char *buf,
 				  const int start_page);
 
-
-__initfunc(int ariadne2_probe(struct device *dev))
+int __init ariadne2_probe(struct device *dev)
 {
     unsigned int key;
     const struct ConfigDev *cd;
@@ -101,8 +100,8 @@
     return -ENODEV;
 }
 
-__initfunc(static int ariadne2_init(struct device *dev, unsigned int key,
-				    unsigned long board))
+static int __init ariadne2_init(struct device *dev, unsigned int key,
+				    unsigned long board)
 {
     int i;
     unsigned char SA_prom[32];
diff -u --recursive --new-file v2.3.9/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c
--- v2.3.9/linux/drivers/net/arlan-proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/arlan-proc.c	Tue Jul  6 10:11:40 1999
@@ -0,0 +1,1059 @@
+#include <linux/config.h>
+#include "arlan.h"
+
+#ifdef CONFIG_PROC_FS
+
+
+#include <linux/sysctl.h>
+#include <linux/version.h>
+
+/* void enableReceive(struct device* dev);
+*/
+
+static  int	arlan_command(struct device * dev, int command);
+
+
+#define ARLAN_STR_SIZE 	0x2ff0
+#define DEV_ARLAN_INFO 	1
+#define DEV_ARLAN 	1
+#define SARLG(type,var) {\
+	pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var));	\
+	}
+
+#define SARLBN(type,var,nn) {\
+	pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\
+	for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\
+	pos += sprintf(arlan_drive_info+pos, "\n");	\
+	}
+
+#define SARLBNpln(type,var,nn) {\
+	for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\
+	}
+
+#define SARLSTR(var,nn) {\
+	char tmpStr[400];\
+	int  tmpLn = nn;\
+	if (nn > 399 ) tmpLn = 399; \
+	memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\
+	tmpStr[tmpLn] = 0; \
+	pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\
+	}
+
+#define SARLUC(var)  	SARLG(u_char, var)
+#define SARLUCN(var,nn) SARLBN(u_char,var, nn)
+#define SARLUS(var)	SARLG(u_short, var)
+#define SARLUSN(var,nn)	SARLBN(u_short,var, nn)
+#define SARLUI(var)	SARLG(u_int, var)
+
+#define SARLUSA(var) {\
+	u_short tmpVar;\
+	memcpy(&tmpVar, (short *) priva->conf->var,2); \
+	pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\
+}
+
+#define SARLUIA(var) {\
+	u_int tmpVar;\
+	memcpy(&tmpVar, (int* )priva->conf->var,4); \
+	pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\
+}
+
+
+const char *arlan_diagnostic_info_string(struct device *dev)
+{
+
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+	u_char diagnosticInfo;
+
+	READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char);
+
+	switch (diagnosticInfo)
+	{
+		case 0xFF:
+			return "Diagnostic info is OK";
+		case 0xFE:
+			return "ERROR EPROM Checksum error ";
+		case 0xFD:
+			return "ERROR Local Ram Test Failed ";
+		case 0xFC:
+			return "ERROR SCC failure ";
+		case 0xFB:
+			return "ERROR BackBone failure ";
+		case 0xFA:
+			return "ERROR tranceiver not found ";
+		case 0xF9:
+			return "ERROR no more address space ";
+		case 0xF8:
+			return "ERROR Checksum error  ";
+		case 0xF7:
+			return "ERROR Missing SS Code";
+		case 0xF6:
+			return "ERROR Invalid config format";
+		case 0xF5:
+			return "ERROR Reserved errorcode F5";
+		case 0xF4:
+			return "ERROR Invalid spreading code/channel number";
+		case 0xF3:
+			return "ERROR Load Code Error";
+		case 0xF2:
+			return "ERROR Reserver errorcode F2 ";
+		case 0xF1:
+			return "ERROR Invalid command receivec by LAN card ";
+		case 0xF0:
+			return "ERROR Invalid parameter found in command ";
+		case 0xEF:
+			return "ERROR On-chip timer failure ";
+		case 0xEE:
+			return "ERROR T410 timer failure ";
+		case 0xED:
+			return "ERROR Too Many TxEnable commands ";
+		case 0xEC:
+			return "ERROR EEPROM error on radio module ";
+		default:
+			return "ERROR unknown Diagnostic info reply code ";
+	  }
+};
+
+static const char *arlan_hardware_type_string(struct device *dev)
+{
+	u_char hardwareType;
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+	READSHM(hardwareType, arlan->hardwareType, u_char);
+	switch (hardwareType)
+	{
+		case 0x00:
+			return "type A450";
+		case 0x01:
+			return "type A650 ";
+		case 0x04:
+			return "type TMA coproc";
+		case 0x0D:
+			return "type A650E ";
+		case 0x18:
+			return "type TMA coproc Australian";
+		case 0x19:
+			return "type A650A ";
+		case 0x26:
+			return "type TMA coproc European";
+		case 0x2E:
+			return "type A655 ";
+		case 0x2F:
+			return "type A655A ";
+		case 0x30:
+			return "type A655E ";
+		case 0x0B:
+			return "type A670 ";
+		case 0x0C:
+			return "type A670E ";
+		case 0x2D:
+			return "type A670A ";
+		case 0x0F:
+			return "type A411T";
+		case 0x16:
+			return "type A411TA";
+		case 0x1B:
+			return "type A440T";
+		case 0x1C:
+			return "type A412T";
+		case 0x1E:
+			return "type A412TA";
+		case 0x22:
+			return "type A411TE";
+		case 0x24:
+			return "type A412TE";
+		case 0x27:
+			return "type A671T ";
+		case 0x29:
+			return "type A671TA ";
+		case 0x2B:
+			return "type A671TE ";
+		case 0x31:
+			return "type A415T ";
+		case 0x33:
+			return "type A415TA ";
+		case 0x35:
+			return "type A415TE ";
+		case 0x37:
+			return "type A672";
+		case 0x39:
+			return "type A672A ";
+		case 0x3B:
+			return "type A672T";
+		case 0x6B:
+			return "type IC2200";
+		default:
+			return "type A672T";
+	}
+}
+
+static void arlan_print_diagnostic_info(struct device *dev)
+{
+	int i;
+	u_char diagnosticInfo;
+	u_short diagnosticOffset;
+	u_char hardwareType;
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+	//  ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info");
+
+	if (READSHMB(arlan->configuredStatusFlag) == 0)
+		printk("Arlan: Card NOT configured\n");
+	else
+		printk("Arlan: Card is configured\n");
+
+	READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char);
+	READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short);
+
+	printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev));
+
+	if (diagnosticInfo != 0xff)
+		printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset);
+
+	printk("arlan: LAN CODE ID = ");
+	for (i = 0; i < 6; i++)
+		DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char);
+	printk("\n");
+
+	printk("arlan: Arlan BroadCast address  = ");
+	for (i = 0; i < 6; i++)
+		DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char);
+	printk("\n");
+
+	READSHM(hardwareType, arlan->hardwareType, u_char);
+	printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev));
+
+
+	DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char);
+	DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char);
+	DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char);
+	DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short);
+	DEBUGSHM(1, "arlan: SID	=%d\n", arlan->SID, u_short);
+	DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short);
+
+	DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char);
+
+	printk("arlan: name= ");
+	IFDEBUG(1)
+	
+	for (i = 0; i < 16; i++)
+	{
+		char c;
+		READSHM(c, arlan->name[i], char);
+		if (c)
+			printk("%c", c);
+	}
+	printk("\n");
+
+//   ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info");
+
+}
+
+
+/******************************		TEST 	MEMORY	**************/
+
+static int arlan_hw_test_memory(struct device *dev)
+{
+	u_char *ptr;
+	int i;
+	int memlen = sizeof(struct arlan_shmem) - 0xF;	/* avoid control register */
+	volatile char *arlan_mem = (char *) (dev->mem_start);
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+	char pattern;
+
+	ptr = NULL;
+
+	/* hold card in reset state */
+	setHardwareReset(dev);
+
+	/* test memory */
+	pattern = 0;
+	for (i = 0; i < memlen; i++)
+		WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char);
+
+	pattern = 0;
+	for (i = 0; i < memlen; i++)
+	{
+		char res;
+		READSHM(res, arlan_mem[i], char);
+		if (res != pattern++)
+		{
+			printk(KERN_ERR "Arlan driver memory test 1 failed \n");
+			return -1;
+		}
+	}
+
+	pattern = 0;
+	for (i = 0; i < memlen; i++)
+		WRITESHM(arlan_mem[i], ~(pattern++), char);
+
+	pattern = 0;
+	for (i = 0; i < memlen; i++)
+	{
+		char res;
+		READSHM(res, arlan_mem[i], char);
+		if (res != ~(pattern++))
+		{
+			printk(KERN_ERR "Arlan driver memory test 2 failed \n");
+			return -1;
+		}
+	}
+
+	/* zero memory */
+	for (i = 0; i < memlen; i++)
+		WRITESHM(arlan_mem[i], 0x00, char);
+
+	IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n");
+
+	/* set reset flag and then release reset */
+	WRITESHM(arlan->resetFlag, 0xff, u_char);
+
+	clearChannelAttention(dev);
+	clearHardwareReset(dev);
+
+	/* wait for reset flag to become zero, we'll wait for two seconds */
+	if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW))
+	{
+		printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int arlan_setup_card_by_book(struct device *dev)
+{
+	u_char irqLevel, configuredStatusFlag;
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+//	ARLAN_DEBUG_ENTRY("arlan_setup_card");
+
+	READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char);
+
+	IFDEBUG(10)
+	if (configuredStatusFlag != 0)
+		IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n");
+	else
+		IFDEBUG(10) printk("arlan: card is NOT configured\n");
+
+	if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff))
+		if (arlan_hw_test_memory(dev))
+			return -1;
+
+	DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char);
+	DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char);
+
+	/* issue nop command - no interupt */
+	arlan_command(dev, ARLAN_COMMAND_NOOP);
+	if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0)
+		return -1;
+
+	IFDEBUG(50) printk("1st Noop successfully executed !!\n");
+
+	/* try to turn on the arlan interrupts */
+	clearClearInterrupt(dev);
+	setClearInterrupt(dev);
+	setInterruptEnable(dev);
+
+	/* issue nop command - with interrupt */
+
+	arlan_command(dev, ARLAN_COMMAND_NOOPINT);
+	if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0)
+		return -1;
+
+
+	IFDEBUG(50) printk("2nd Noop successfully executed !!\n");
+
+	READSHM(irqLevel, arlan->irqLevel, u_char)
+	
+	if (irqLevel != dev->irq)
+	{
+		IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel);
+		printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq);
+		dev->irq = irqLevel;
+	}
+	else
+		IFDEBUG(2) printk("irq level is OK\n");
+
+
+	IFDEBUG(3) arlan_print_diagnostic_info(dev);
+
+	arlan_command(dev, ARLAN_COMMAND_CONF);
+
+	READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char);
+	if (configuredStatusFlag == 0)
+	{
+		printk(KERN_WARNING "arlan configure failed\n");
+		return -1;
+	}
+	arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW);
+	arlan_command(dev, ARLAN_COMMAND_RX);
+	arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW);
+	printk(KERN_NOTICE "%s: arlan driver version %s loaded\n",
+	       dev->name, arlan_version);
+
+//	ARLAN_DEBUG_EXIT("arlan_setup_card");
+
+	return 0;		/* no errors */
+}
+
+
+#ifdef ARLAN_PROC_INTERFACE
+#ifdef ARLAN_PROC_SHM_DUMP
+
+static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0";
+
+static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp,
+		      void *buffer, size_t * lenp)
+{
+	int i;
+	int retv, pos, devnum;
+	struct arlan_private *priva = NULL;
+	struct device *dev;
+	pos = 0;
+	if (write)
+	{
+		printk("wrirte: ");
+		for (i = 0; i < 100; i++)
+			printk("adi %x \n", arlan_drive_info[i]);
+	}
+	if (ctl->procname == NULL || arlan_drive_info == NULL)
+	{
+		printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n ");
+		return -1;
+	}
+	devnum = ctl->procname[5] - '0';
+	if (devnum < 0 || devnum > MAX_ARLANS - 1)
+	{
+		printk(KERN_WARNING "too strange devnum in procfs parse\n ");
+		return -1;
+	}
+	else if (arlan_device[devnum] == NULL)
+	{
+		if (ctl->procname)
+			pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname);
+		pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+		goto final;
+	}
+	else
+		priva = arlan_device[devnum]->priv;
+
+	if (priva == NULL)
+	{
+		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+		return -1;
+	}
+	dev = arlan_device[devnum];
+
+	memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+
+	pos = sprintf(arlan_drive_info, "Arlan  info \n");
+	/* Header Signature */
+	SARLSTR(textRegion, 48);
+	SARLUC(resetFlag);
+	pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev));
+	SARLUC(diagnosticInfo);
+	SARLUS(diagnosticOffset);
+	SARLUCN(_1, 12);
+	SARLUCN(lanCardNodeId, 6);
+	SARLUCN(broadcastAddress, 6);
+	pos += sprintf(arlan_drive_info + pos, "hardwareType =\t  %s \n", arlan_hardware_type_string(dev));
+	SARLUC(hardwareType);
+	SARLUC(majorHardwareVersion);
+	SARLUC(minorHardwareVersion);
+	SARLUC(radioModule);
+	SARLUC(defaultChannelSet);
+	SARLUCN(_2, 47);
+
+	/* Control/Status Block - 0x0080 */
+	SARLUC(interruptInProgress);
+	SARLUC(cntrlRegImage);
+
+	SARLUCN(_3, 14);
+	SARLUC(commandByte);
+	SARLUCN(commandParameter, 15);
+
+	/* Receive Status - 0x00a0 */
+	SARLUC(rxStatus);
+	SARLUC(rxFrmType);
+	SARLUS(rxOffset);
+	SARLUS(rxLength);
+	SARLUCN(rxSrc, 6);
+	SARLUC(rxBroadcastFlag);
+	SARLUC(rxQuality);
+	SARLUC(scrambled);
+	SARLUCN(_4, 1);
+
+	/* Transmit Status - 0x00b0 */
+	SARLUC(txStatus);
+	SARLUC(txAckQuality);
+	SARLUC(numRetries);
+	SARLUCN(_5, 14);
+	SARLUCN(registeredRouter, 6);
+	SARLUCN(backboneRouter, 6);
+	SARLUC(registrationStatus);
+	SARLUC(configuredStatusFlag);
+	SARLUCN(_6, 1);
+	SARLUCN(ultimateDestAddress, 6);
+	SARLUCN(immedDestAddress, 6);
+	SARLUCN(immedSrcAddress, 6);
+	SARLUS(rxSequenceNumber);
+	SARLUC(assignedLocaltalkAddress);
+	SARLUCN(_7, 27);
+
+	/* System Parameter Block */
+
+	/* - Driver Parameters (Novell Specific) */
+
+	SARLUS(txTimeout);
+	SARLUS(transportTime);
+	SARLUCN(_8, 4);
+
+	/* - Configuration Parameters */
+	SARLUC(irqLevel);
+	SARLUC(spreadingCode);
+	SARLUC(channelSet);
+	SARLUC(channelNumber);
+	SARLUS(radioNodeId);
+	SARLUCN(_9, 2);
+	SARLUC(scramblingDisable);
+	SARLUC(radioType);
+	SARLUS(routerId);
+	SARLUCN(_10, 9);
+	SARLUC(txAttenuation);
+	SARLUIA(systemId);
+	SARLUS(globalChecksum);
+	SARLUCN(_11, 4);
+	SARLUS(maxDatagramSize);
+	SARLUS(maxFrameSize);
+	SARLUC(maxRetries);
+	SARLUC(receiveMode);
+	SARLUC(priority);
+	SARLUC(rootOrRepeater);
+	SARLUCN(specifiedRouter, 6);
+	SARLUS(fastPollPeriod);
+	SARLUC(pollDecay);
+	SARLUSA(fastPollDelay);
+	SARLUC(arlThreshold);
+	SARLUC(arlDecay);
+	SARLUCN(_12, 1);
+	SARLUS(specRouterTimeout);
+	SARLUCN(_13, 5);
+
+	/* Scrambled Area */
+	SARLUIA(SID);
+	SARLUCN(encryptionKey, 12);
+	SARLUIA(_14);
+	SARLUSA(waitTime);
+	SARLUSA(lParameter);
+	SARLUCN(_15, 3);
+	SARLUS(headerSize);
+	SARLUS(sectionChecksum);
+
+	SARLUC(registrationMode);
+	SARLUC(registrationFill);
+	SARLUS(pollPeriod);
+	SARLUS(refreshPeriod);
+	SARLSTR(name, 16);
+	SARLUCN(NID, 6);
+	SARLUC(localTalkAddress);
+	SARLUC(codeFormat);
+	SARLUC(numChannels);
+	SARLUC(channel1);
+	SARLUC(channel2);
+	SARLUC(channel3);
+	SARLUC(channel4);
+	SARLUCN(SSCode, 59);
+
+/*      SARLUCN( _16, 0x140);
+ */
+	/* Statistics Block - 0x0300 */
+	SARLUC(hostcpuLock);
+	SARLUC(lancpuLock);
+	SARLUCN(resetTime, 18);
+	SARLUIA(numDatagramsTransmitted);
+	SARLUIA(numReTransmissions);
+	SARLUIA(numFramesDiscarded);
+	SARLUIA(numDatagramsReceived);
+	SARLUIA(numDuplicateReceivedFrames);
+	SARLUIA(numDatagramsDiscarded);
+	SARLUS(maxNumReTransmitDatagram);
+	SARLUS(maxNumReTransmitFrames);
+	SARLUS(maxNumConsecutiveDuplicateFrames);
+	/* misaligned here so we have to go to characters */
+	SARLUIA(numBytesTransmitted);
+	SARLUIA(numBytesReceived);
+	SARLUIA(numCRCErrors);
+	SARLUIA(numLengthErrors);
+	SARLUIA(numAbortErrors);
+	SARLUIA(numTXUnderruns);
+	SARLUIA(numRXOverruns);
+	SARLUIA(numHoldOffs);
+	SARLUIA(numFramesTransmitted);
+	SARLUIA(numFramesReceived);
+	SARLUIA(numReceiveFramesLost);
+	SARLUIA(numRXBufferOverflows);
+	SARLUIA(numFramesDiscardedAddrMismatch);
+	SARLUIA(numFramesDiscardedSIDMismatch);
+	SARLUIA(numPollsTransmistted);
+	SARLUIA(numPollAcknowledges);
+	SARLUIA(numStatusTimeouts);
+	SARLUIA(numNACKReceived);
+	SARLUS(auxCmd);
+	SARLUCN(dumpPtr, 4);
+	SARLUC(dumpVal);
+	SARLUC(wireTest);
+	
+	/* next 4 seems too long for procfs, over single page ?
+	SARLUCN( _17, 0x86);
+	SARLUCN( txBuffer, 0x800);
+	SARLUCN( rxBuffer,  0x800); 
+	SARLUCN( _18, 0x0bff);
+	 */
+
+	pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x");
+	for (i = 0; i < 0x50; i++)
+		pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]);
+	pos += sprintf(arlan_drive_info + pos, "\n");
+
+	SARLUC(configStatus);
+	SARLUC(_22);
+	SARLUC(progIOCtrl);
+	SARLUC(shareMBase);
+	SARLUC(controlRegister);
+
+	pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos);
+	if (ctl)
+		if (ctl->procname)
+			pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname);
+final:
+	*lenp = pos;
+
+	if (!write)
+		retv = proc_dostring(ctl, write, filp, buffer, lenp);
+	else
+	{
+		*lenp = 0;
+		return -1;
+	}
+	return retv;
+}
+
+
+static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp,
+			    void *buffer, size_t * lenp)
+{
+	int i;
+	int retv, pos, devnum;
+	struct arlan_private *priva = NULL;
+
+	pos = 0;
+	devnum = ctl->procname[5] - '0';
+	if (arlan_device[devnum] == NULL)
+	{
+		pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+		goto final;
+	}
+	else
+		priva = arlan_device[devnum]->priv;
+	if (priva == NULL)
+	{
+		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+		return -1;
+	}
+	memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+	SARLUCN(_16, 0xC0);
+	SARLUCN(_17, 0x6A);
+	SARLUCN(_18, 14);
+	SARLUCN(_19, 0x86);
+	SARLUCN(_21, 0x3fd);
+
+final:
+	*lenp = pos;
+	retv = proc_dostring(ctl, write, filp, buffer, lenp);
+	return retv;
+}
+
+static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp,
+			    void *buffer, size_t * lenp)
+{
+	int i;
+	int retv, pos, devnum;
+	struct arlan_private *priva = NULL;
+
+	pos = 0;
+	devnum = ctl->procname[5] - '0';
+	if (arlan_device[devnum] == NULL)
+	{
+		  pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+		  goto final;
+	}
+	else
+		priva = arlan_device[devnum]->priv;
+	if (priva == NULL)
+	{
+		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+		return -1;
+	}
+	memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+	SARLBNpln(u_char, txBuffer, 0x800);
+final:
+	*lenp = pos;
+	retv = proc_dostring(ctl, write, filp, buffer, lenp);
+	return retv;
+}
+
+static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp,
+			    void *buffer, size_t * lenp)
+{
+	int i;
+	int retv, pos, devnum;
+	struct arlan_private *priva = NULL;
+
+	pos = 0;
+	devnum = ctl->procname[5] - '0';
+	if (arlan_device[devnum] == NULL)
+	{
+		  pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+		  goto final;
+	} else
+		priva = arlan_device[devnum]->priv;
+	if (priva == NULL)
+	{
+		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+		return -1;
+	}
+	memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+	SARLBNpln(u_char, rxBuffer, 0x800);
+final:
+	*lenp = pos;
+	retv = proc_dostring(ctl, write, filp, buffer, lenp);
+	return retv;
+}
+
+static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp,
+			void *buffer, size_t * lenp)
+{
+	int i;
+	int retv, pos, devnum;
+	struct arlan_private *priva = NULL;
+
+	pos = 0;
+	devnum = ctl->procname[5] - '0';
+	if (arlan_device[devnum] == NULL)
+	{
+		pos += sprintf(arlan_drive_info + pos, "No device found here \n");
+		goto final;
+	}
+	else
+		priva = arlan_device[devnum]->priv;
+	if (priva == NULL)
+	{
+		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
+		return -1;
+	}
+	memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem));
+	SARLBNpln(u_char, _18, 0x800);
+
+final:
+	*lenp = pos;
+	retv = proc_dostring(ctl, write, filp, buffer, lenp);
+	return retv;
+}
+
+
+#endif				/* #ifdef ARLAN_PROC_SHM_DUMP */
+
+
+static char conf_reset_result[200];
+
+static int arlan_configure(ctl_table * ctl, int write, struct file *filp,
+		    void *buffer, size_t * lenp)
+{
+	int pos = 0;
+	int devnum = ctl->procname[6] - '0';
+	struct arlan_private *priv;
+
+	if (devnum < 0 || devnum > MAX_ARLANS - 1)
+	{
+		  printk(KERN_WARNING "too strange devnum in procfs parse\n ");
+		  return -1;
+	}
+	else if (arlan_device[devnum] != NULL)
+	{
+		  priv = arlan_device[devnum]->priv;
+
+		  arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF);
+	}
+	else
+		return -1;
+
+	*lenp = pos;
+	return proc_dostring(ctl, write, filp, buffer, lenp);
+}
+
+int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp,
+		       void *buffer, size_t * lenp)
+{
+	int pos = 0;
+	int devnum = ctl->procname[5] - '0';
+	struct arlan_private *priv;
+
+	if (devnum < 0 || devnum > MAX_ARLANS - 1)
+	{
+		  printk(KERN_WARNING "too strange devnum in procfs parse\n ");
+		  return -1;
+	}
+	else if (arlan_device[devnum] != NULL)
+	{
+		priv = arlan_device[devnum]->priv;
+		arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET);
+
+	} else
+		return -1;
+	*lenp = pos + 3;
+	return proc_dostring(ctl, write, filp, buffer, lenp);
+}
+
+
+/* Place files in /proc/sys/dev/arlan */
+#define CTBLN(num,card,nam) \
+        {num , #nam, &(arlan_conf[card].nam), \
+         sizeof(int), 0600, NULL, &proc_dointvec}
+
+
+#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\
+	CTBLN(1,cardNo,spreadingCode),\
+	CTBLN(2,cardNo, channelNumber),\
+	CTBLN(3,cardNo, scramblingDisable),\
+	CTBLN(4,cardNo, txAttenuation),\
+	CTBLN(5,cardNo, systemId), \
+	CTBLN(6,cardNo, maxDatagramSize),\
+	CTBLN(7,cardNo, maxFrameSize),\
+	CTBLN(8,cardNo, maxRetries),\
+	CTBLN(9,cardNo, receiveMode),\
+	CTBLN(10,cardNo, priority),\
+	CTBLN(11,cardNo, rootOrRepeater),\
+	CTBLN(12,cardNo, SID),\
+	CTBLN(13,cardNo, registrationMode),\
+	CTBLN(14,cardNo, registrationFill),\
+	CTBLN(15,cardNo, localTalkAddress),\
+	CTBLN(16,cardNo, codeFormat),\
+	CTBLN(17,cardNo, numChannels),\
+	CTBLN(18,cardNo, channel1),\
+	CTBLN(19,cardNo, channel2),\
+	CTBLN(20,cardNo, channel3),\
+	CTBLN(21,cardNo, channel4),\
+	CTBLN(22,cardNo, txClear),\
+	CTBLN(23,cardNo, txRetries),\
+	CTBLN(24,cardNo, txRouting),\
+	CTBLN(25,cardNo, txScrambled),\
+	CTBLN(26,cardNo, rxParameter),\
+	CTBLN(27,cardNo, txTimeoutMs),\
+	CTBLN(28,cardNo, waitCardTimeout),\
+	CTBLN(29,cardNo, channelSet), \
+	{30, "name", arlan_conf[cardNo].siteName, \
+                16, 0600, NULL, &proc_dostring},\
+	CTBLN(31,cardNo,waitTime),\
+	CTBLN(32,cardNo,lParameter),\
+	CTBLN(33,cardNo,_15),\
+	CTBLN(34,cardNo,headerSize),\
+	CTBLN(35,cardNo,async),\
+	CTBLN(36,cardNo,tx_delay_ms),\
+	CTBLN(37,cardNo,retries),\
+	CTBLN(38,cardNo,ReTransmitPacketMaxSize),\
+	CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\
+	CTBLN(40,cardNo,fastReTransCount),\
+	CTBLN(41,cardNo,driverRetransmissions),\
+	CTBLN(42,cardNo,txAckTimeoutMs),\
+	CTBLN(43,cardNo,registrationInterrupts),\
+	CTBLN(44,cardNo,hardwareType),\
+	CTBLN(45,cardNo,radioType),\
+	CTBLN(46,cardNo,writeEEPROM),\
+	CTBLN(47,cardNo,writeRadioType),\
+	{48, "entry_exit_debug", &arlan_entry_and_exit_debug, \
+                sizeof(int), 0600, NULL, &proc_dointvec},\
+	{49, "debug", &arlan_debug, \
+                sizeof(int), 0600, NULL, &proc_dointvec},\
+	CTBLN(50,cardNo,in_speed),\
+	CTBLN(51,cardNo,out_speed),\
+	CTBLN(52,cardNo,in_speed10),\
+	CTBLN(53,cardNo,out_speed10),\
+	CTBLN(54,cardNo,in_speed_max),\
+	CTBLN(55,cardNo,out_speed_max),\
+	CTBLN(56,cardNo,measure_rate),\
+	CTBLN(57,cardNo,pre_Command_Wait),\
+	CTBLN(58,cardNo,rx_tweak1),\
+	CTBLN(59,cardNo,rx_tweak2),\
+	CTBLN(60,cardNo,tx_queue_len),\
+
+
+
+static ctl_table arlan_conf_table0[] =
+{
+	ARLAN_SYSCTL_TABLE_TOTAL(0)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+	{150, "arlan0-txRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+	{151, "arlan0-rxRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+	{152, "arlan0-18", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+	{153, "arlan0-ring", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+	{154, "arlan0-shm-cpy", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+	{155, "config0", &conf_reset_result, \
+	 100, 0400, NULL, &arlan_configure}, \
+	{156, "reset0", &conf_reset_result, \
+	 100, 0400, NULL, &arlan_sysctl_reset}, \
+	{0}
+};
+
+static ctl_table arlan_conf_table1[] =
+{
+
+	ARLAN_SYSCTL_TABLE_TOTAL(1)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+	{150, "arlan1-txRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+	{151, "arlan1-rxRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+	{152, "arlan1-18", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+	{153, "arlan1-ring", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+	{154, "arlan1-shm-cpy", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+	{155, "config1", &conf_reset_result,
+	 100, 0400, NULL, &arlan_configure},
+	{156, "reset1", &conf_reset_result,
+	 100, 0400, NULL, &arlan_sysctl_reset},
+	{0}
+};
+
+static ctl_table arlan_conf_table2[] =
+{
+
+	ARLAN_SYSCTL_TABLE_TOTAL(2)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+	{150, "arlan2-txRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+	{151, "arlan2-rxRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+	{152, "arlan2-18", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+	{153, "arlan2-ring", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+	{154, "arlan2-shm-cpy", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+	{155, "config2", &conf_reset_result,
+	 100, 0400, NULL, &arlan_configure},
+	{156, "reset2", &conf_reset_result,
+	 100, 0400, NULL, &arlan_sysctl_reset},
+	{0}
+};
+
+static ctl_table arlan_conf_table3[] =
+{
+
+	ARLAN_SYSCTL_TABLE_TOTAL(3)
+
+#ifdef ARLAN_PROC_SHM_DUMP
+	{150, "arlan3-txRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing},
+	{151, "arlan3-rxRing", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing},
+	{152, "arlan3-18", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18},
+	{153, "arlan3-ring", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719},
+	{154, "arlan3-shm-cpy", &arlan_drive_info,
+	 ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info},
+#endif
+	{155, "config3", &conf_reset_result,
+	 100, 0400, NULL, &arlan_configure},
+	{156, "reset3", &conf_reset_result,
+	 100, 0400, NULL, &arlan_sysctl_reset},
+	{0}
+};
+
+
+
+static ctl_table arlan_table[] =
+{
+	{0, "arlan0", NULL, 0, 0600, arlan_conf_table0},
+	{0, "arlan1", NULL, 0, 0600, arlan_conf_table1},
+	{0, "arlan2", NULL, 0, 0600, arlan_conf_table2},
+	{0, "arlan3", NULL, 0, 0600, arlan_conf_table3},
+	{0}
+};
+
+#else
+
+static ctl_table arlan_table[MAX_ARLANS + 1] =
+{
+	{0}
+};
+#endif
+#endif
+
+static int mmtu = 1234;
+
+static ctl_table arlan_root_table[] =
+{
+	{254, "arlan", NULL, 0, 0555, arlan_table},
+	{0}
+};
+
+/* Make sure that /proc/sys/dev is there */
+static ctl_table arlan_device_root_table[] =
+{
+	{CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table},
+	{0}
+};
+
+
+
+static struct ctl_table_header *arlan_device_sysctl_header = NULL;
+
+int init_arlan_proc(void)
+{
+
+	int i = 0;
+	if (arlan_device_sysctl_header)
+		return 0;
+	for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++)
+		arlan_table[i].ctl_name = i + 1;
+	arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0);
+	if (!arlan_device_sysctl_header)
+		return -1;
+
+	return 0;
+
+};
+
+
+
+#ifdef MODULE
+
+int init_module(void)
+{
+
+	return init_arlan_proc();
+};
+
+void cleanup_module(void)
+{
+	unregister_sysctl_table(arlan_device_sysctl_header);
+	arlan_device_sysctl_header = NULL;
+
+	return;
+};
+
+#endif				// MODULE
diff -u --recursive --new-file v2.3.9/linux/drivers/net/arlan.c linux/drivers/net/arlan.c
--- v2.3.9/linux/drivers/net/arlan.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/arlan.c	Tue Jul  6 10:11:40 1999
@@ -0,0 +1,2079 @@
+/*
+ *  Copyright (C) 1997 Cullen Jennings
+ *  Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500        
+ *  Gnu Public License applies
+ * This module provides support for the Arlan 655 card made by Aironet
+ */
+
+#include <linux/config.h>
+#include "arlan.h"
+
+static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee  Oct'98, http://www.ylenurme.ee/~elmer/655/";
+
+struct device *arlan_device[MAX_ARLANS];
+int last_arlan = 0;
+
+static int SID = SIDUNKNOWN;
+static int radioNodeId = radioNodeIdUNKNOWN;
+static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
+static char *siteName = siteNameUNKNOWN;
+static int irq = irqUNKNOWN;
+static int mem = memUNKNOWN;
+static int arlan_debug = debugUNKNOWN;
+static int probe = probeUNKNOWN;
+static int numDevices = numDevicesUNKNOWN;
+static int testMemory = testMemoryUNKNOWN;
+static int spreadingCode = spreadingCodeUNKNOWN;
+static int channelNumber = channelNumberUNKNOWN;
+static int channelSet = channelSetUNKNOWN;
+static int systemId = systemIdUNKNOWN;
+static int registrationMode = registrationModeUNKNOWN;
+static int txScrambled = 1;
+static int keyStart = 0;
+static int mdebug = 0;
+static int tx_delay_ms = 0;
+static int retries = 5;
+static int async = 1;
+static int tx_queue_len = 1;
+static int arlan_entry_debug = 0;
+static int arlan_exit_debug = 0;
+static int arlan_entry_and_exit_debug = 0;
+static int arlan_EEPROM_bad = 0;
+
+#if LINUX_VERSION_CODE > 0x20100
+MODULE_PARM(irq, "i");
+MODULE_PARM(mem, "i");
+MODULE_PARM(probe, "i");
+MODULE_PARM(arlan_debug, "i");
+MODULE_PARM(numDevices, "i");
+MODULE_PARM(testMemory, "i");
+MODULE_PARM(spreadingCode, "i");
+MODULE_PARM(channelNumber, "i");
+MODULE_PARM(channelSet, "i");
+MODULE_PARM(systemId, "i");
+MODULE_PARM(registrationMode, "i");
+MODULE_PARM(radioNodeId, "i");
+MODULE_PARM(SID, "i");
+MODULE_PARM(txScrambled, "i");
+MODULE_PARM(keyStart, "i");
+MODULE_PARM(mdebug, "i");
+MODULE_PARM(tx_delay_ms, "i");
+MODULE_PARM(retries, "i");
+MODULE_PARM(async, "i");
+MODULE_PARM(tx_queue_len, "i");
+MODULE_PARM(arlan_entry_debug, "i");
+MODULE_PARM(arlan_exit_debug, "i");
+MODULE_PARM(arlan_entry_and_exit_debug, "i");
+MODULE_PARM(arlan_EEPROM_bad, "i");
+
+EXPORT_SYMBOL(arlan_device);
+EXPORT_SYMBOL(last_arlan);
+
+
+//        #warning kernel 2.1.110 tested
+#define myATOMIC_INIT(a,b) atomic_set(&(a),b)
+#define __initfunctio(a)                __initfunc(a)
+
+#else
+#define test_and_set_bit	set_bit
+#define __initfunctio(a)        a
+#if LINUX_VERSION_CODE != 0x20024
+ //        #warning kernel  2.0.36  tested
+#endif
+#define myATOMIC_INIT(a,b) a = b;
+
+#endif
+
+struct arlan_conf_stru arlan_conf[MAX_ARLANS];
+int arlans_found = 0;
+
+static  int 	arlan_probe_here(struct device *dev, int ioaddr);
+static  int 	arlan_open(struct device *dev);
+static  int 	arlan_tx(struct sk_buff *skb, struct device *dev);
+static  void 	arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static  int 	arlan_close(struct device *dev);
+static  struct enet_statistics *
+		arlan_statistics		(struct device *dev);
+static  void 	arlan_set_multicast		(struct device *dev);
+static  int 	arlan_hw_tx			(struct device* dev, char *buf, int length );
+static  int	arlan_hw_config			(struct device * dev);
+static  void 	arlan_tx_done_interrupt		(struct device * dev, int status);
+static  void	arlan_rx_interrupt		(struct device * dev, u_char rxStatus, u_short, u_short);
+static  void	arlan_process_interrupt		(struct device * dev);
+static  int	arlan_command(struct device * dev, int command);
+
+EXPORT_SYMBOL(arlan_command);
+
+extern inline long long arlan_time(void)
+{
+	struct timeval timev;
+	do_gettimeofday(&timev);
+	return ((long long) timev.tv_sec * 1000000 + timev.tv_usec);
+};
+
+#ifdef ARLAN_ENTRY_EXIT_DEBUGING
+#define ARLAN_DEBUG_ENTRY(name) \
+	{\
+	struct timeval timev;\
+	do_gettimeofday(&timev);\
+		if (arlan_entry_debug || arlan_entry_and_exit_debug)\
+			printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\
+	}
+#define ARLAN_DEBUG_EXIT(name) \
+	{\
+	struct timeval timev;\
+	do_gettimeofday(&timev);\
+		if (arlan_exit_debug || arlan_entry_and_exit_debug)\
+			printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\
+	}
+#else
+#define ARLAN_DEBUG_ENTRY(name)
+#define ARLAN_DEBUG_EXIT(name)
+#endif
+
+
+#define arlan_interrupt_ack(dev)\
+        clearClearInterrupt(dev);\
+        setClearInterrupt(dev);
+
+
+#define ARLAN_COMMAND_LOCK(dev) \
+	if (atomic_dec_and_test(&((struct arlan_private * )dev->priv)->card_users))\
+   		arlan_wait_command_complete_short(dev,__LINE__);
+#define ARLAN_COMMAND_UNLOCK(dev) \
+	atomic_inc(&((struct arlan_private * )dev->priv)->card_users);
+
+
+#define ARLAN_COMMAND_INC(dev) \
+ 	{((struct arlan_private *) dev->priv)->under_command++;}
+#define ARLAN_COMMAND_ZERO(dev) \
+ 	{((struct arlan_private *) dev->priv)->under_command =0;}
+#define ARLAN_UNDER_COMMAND(dev)\
+	(((struct arlan_private *) dev->priv)->under_command)
+
+#define ARLAN_COMMAND_START(dev) ARLAN_COMMAND_INC(dev)
+#define ARLAN_COMMAND_END(dev) ARLAN_COMMAND_ZERO(dev)
+#define ARLAN_TOGGLE_START(dev)\
+ 	{((struct arlan_private *) dev->priv)->under_toggle++;}
+#define ARLAN_TOGGLE_END(dev)\
+ 	{((struct arlan_private *) dev->priv)->under_toggle=0;}
+#define ARLAN_UNDER_TOGGLE(dev)\
+ 	(((struct arlan_private *) dev->priv)->under_toggle)
+
+
+
+extern inline int arlan_drop_tx(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	priv->stats.tx_errors++;
+	if (priv->Conf->tx_delay_ms)
+	{
+		priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1;
+	}
+	else
+	{
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_TX;
+		TXHEAD(dev).offset = 0;
+		TXTAIL(dev).offset = 0;
+		priv->txLast = 0;
+		priv->txOffset = 0;
+		priv->bad = 0;
+		if (!priv->under_reset && !priv->under_config)
+		{
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+	}
+	return 1;
+};
+
+
+static int arlan_command(struct device *dev, int command_p)
+{
+
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	int udelayed = 0;
+	int i = 0;
+	long long time_mks = arlan_time();
+
+	ARLAN_DEBUG_ENTRY("arlan_command");
+
+	if (priv->card_polling_interval)
+		priv->card_polling_interval = 1;
+
+	if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+		printk(KERN_DEBUG "arlan_command, %lx lock %x  commandByte %x waiting %x incoming %x \n",
+		jiffies, priv->command_lock, READSHMB(arlan->commandByte),
+		       priv->waiting_command_mask, command_p);
+
+	priv->waiting_command_mask |= command_p;
+
+	if (priv->waiting_command_mask & ARLAN_COMMAND_RESET)
+		if (jiffies - priv->lastReset < 5 * HZ)
+			priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET;
+
+	if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK)
+	{
+		arlan_interrupt_ack(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK;
+	}
+	if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE)
+	{
+		setInterruptEnable(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE;
+	}
+
+	/* Card access serializing lock */
+
+	if (test_and_set_bit(0, (void *) &priv->command_lock))
+	{
+		if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+			printk(KERN_DEBUG "arlan_command: entered when command locked \n");
+		goto command_busy_end;
+	}
+	/* Check cards status and waiting */
+
+	if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW))
+	{
+		while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW))
+		{
+			if (READSHMB(arlan->resetFlag) ||
+				READSHMB(arlan->commandByte))	/* || 
+								   (readControlRegister(dev) & ARLAN_ACCESS))
+								 */
+				udelay(40);
+			else
+				priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW);
+
+			udelayed++;
+
+			if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW)
+			{
+				if (udelayed * 40 > 1000000)
+				{
+					printk(KERN_ERR "%s long wait too long \n", dev->name);
+					priv->waiting_command_mask |= ARLAN_COMMAND_RESET;
+					break;
+				}
+			}
+			else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW)
+			{
+				if (udelayed * 40 > 1000)
+				{
+					printk(KERN_ERR "%s short wait too long \n", dev->name);
+					goto bad_end;
+				}
+			}
+		}
+	}
+	else
+	{
+		i = 0;
+		while ((READSHMB(arlan->resetFlag) ||
+			READSHMB(arlan->commandByte)) &&
+			conf->pre_Command_Wait > (i++) * 10)
+			udelay(10);
+
+
+		if ((READSHMB(arlan->resetFlag) ||
+			READSHMB(arlan->commandByte)) &&
+			!(priv->waiting_command_mask & ARLAN_COMMAND_RESET))
+		{
+			goto card_busy_end;
+		}
+	}
+	if (priv->waiting_command_mask & ARLAN_COMMAND_RESET)
+	{
+		priv->under_reset = 1;
+		dev->start = 0;
+	}
+	if (priv->waiting_command_mask & ARLAN_COMMAND_CONF)
+	{
+		priv->under_config = 1;
+		dev->start = 0;
+	}
+
+	/* Issuing command */
+	arlan_lock_card_access(dev);
+	if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP)
+	{
+	//     if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER))
+		setPowerOn(dev);
+		arlan_interrupt_lancpu(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP;
+		priv->waiting_command_mask |= ARLAN_COMMAND_RESET;
+		priv->card_polling_interval = HZ / 10;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE)
+	{
+		WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE);
+		arlan_interrupt_lancpu(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE;
+		priv->card_polling_interval = HZ / 10;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT)
+	{
+		if (priv->rx_command_given)
+		{
+			WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT);
+			arlan_interrupt_lancpu(dev);
+			priv->rx_command_given = 0;
+		}
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT;
+		priv->card_polling_interval = 1;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT)
+	{
+		if (priv->tx_command_given)
+		{
+			WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT);
+			arlan_interrupt_lancpu(dev);
+			priv->tx_command_given = 0;
+		}
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT;
+		priv->card_polling_interval = 1;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET)
+	{
+		arlan_drop_tx(dev);
+		if (priv->tx_command_given || priv->rx_command_given)
+		{
+			printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name);
+		};
+		if (arlan_debug & ARLAN_DEBUG_RESET)
+			printk(KERN_ERR "%s: Doing chip reset\n", dev->name);
+		priv->lastReset = jiffies;
+		WRITESHM(arlan->commandByte, 0, u_char);
+		/* hold card in reset state */
+		setHardwareReset(dev);
+		/* set reset flag and then release reset */
+		WRITESHM(arlan->resetFlag, 0xff, u_char);
+		clearChannelAttention(dev);
+		clearHardwareReset(dev);
+		priv->numResets++;
+		priv->card_polling_interval = HZ / 4;
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET;
+		priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK;
+//		priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; 
+//		priv->waiting_command_mask |= ARLAN_COMMAND_RX;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK)
+	{
+		clearHardwareReset(dev);
+		clearClearInterrupt(dev);
+		setClearInterrupt(dev);
+		setInterruptEnable(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK;
+		priv->waiting_command_mask |= ARLAN_COMMAND_CONF;
+		priv->under_config = 1;
+		priv->under_reset = 0;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE)
+	{
+		setInterruptEnable(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF)
+	{
+		if (priv->tx_command_given || priv->rx_command_given)
+		{
+			printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name);
+		}
+		dev->start = 0;
+		arlan_drop_tx(dev);
+		setInterruptEnable(dev);
+		arlan_hw_config(dev);
+		arlan_interrupt_lancpu(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF;
+		priv->card_polling_interval = HZ / 10;
+//		priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK;   
+//		priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; 
+		priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT)
+	{
+		if (READSHMB(arlan->configuredStatusFlag) != 0 &&
+			READSHMB(arlan->diagnosticInfo) == 0xff)
+		{
+			priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT;
+			priv->waiting_command_mask |= ARLAN_COMMAND_RX;
+			priv->card_polling_interval = HZ / 10;
+			priv->tx_command_given = 0;
+			priv->under_config = 0;
+			if (dev->tbusy || !dev->start)
+			{
+				dev->tbusy = 0;
+				dev->start = 1;
+				mark_bh(NET_BH);
+			};
+		}
+		else
+		{
+			priv->card_polling_interval = 1;
+			if (arlan_debug & ARLAN_DEBUG_TIMING)
+				printk(KERN_ERR "configure delayed \n");
+		}
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_RX)
+	{
+		if (!registrationBad(dev))
+		{
+			setInterruptEnable(dev);
+			memset_io((void *) arlan->commandParameter, 0, 0xf);
+			WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE);
+			WRITESHMB(arlan->commandParameter[0], conf->rxParameter);
+			arlan_interrupt_lancpu(dev);
+			priv->rx_command_given;
+			priv->last_rx_time = arlan_time();
+			priv->waiting_command_mask &= ~ARLAN_COMMAND_RX;
+			priv->card_polling_interval = 1;
+		}
+		else
+			priv->card_polling_interval = 2;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_TX)
+	{
+		if (!test_and_set_bit(0, (void *) &priv->tx_command_given))
+		{
+			if ((time_mks - priv->last_tx_time > conf->rx_tweak1) ||
+				(time_mks - priv->last_rx_int_ack_time < conf->rx_tweak2))
+			{
+				setInterruptEnable(dev);
+				memset_io((void *) arlan->commandParameter, 0, 0xf);
+				WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT);
+				memcpy_toio((void *) arlan->commandParameter, &TXLAST(dev), 14);
+//				for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i]));
+				priv->last_command_was_rx = 0;
+				priv->tx_last_sent = jiffies;
+				arlan_interrupt_lancpu(dev);
+				priv->last_tx_time = arlan_time();
+				priv->tx_command_given = 1;
+				priv->waiting_command_mask &= ~ARLAN_COMMAND_TX;
+				priv->card_polling_interval = 1;
+			}
+			else
+			{
+				priv->tx_command_given = 0;
+				priv->card_polling_interval = 1;
+			}
+		} 
+		else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+			printk(KERN_ERR "tx command when tx chain locked \n");
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT)
+	{
+		{
+			WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT);
+		}
+		arlan_interrupt_lancpu(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT;
+		priv->card_polling_interval = HZ / 3;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP)
+	{
+		WRITESHMB(arlan->commandByte, ARLAN_COM_NOP);
+		arlan_interrupt_lancpu(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP;
+		priv->card_polling_interval = HZ / 3;
+	}
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL)
+	{
+		WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL);
+		arlan_interrupt_lancpu(dev);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL;
+		priv->card_polling_interval = HZ / 3;
+	} 
+	else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN)
+	{
+		setPowerOff(dev);
+		if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+			printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name);
+		priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN;
+		priv->card_polling_interval = 3 * HZ;
+	}
+	arlan_unlock_card_access(dev);
+	for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++)
+		udelay(10);
+	if (READSHMB(arlan->commandByte))
+		if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+			printk(KERN_ERR "card busy leaving command %x \n", priv->waiting_command_mask);
+
+	priv->command_lock = 0;
+	ARLAN_DEBUG_EXIT("arlan_command");
+	priv->last_command_buff_free_time = jiffies;
+	return 0;
+
+card_busy_end:
+	if (jiffies - priv->last_command_buff_free_time > HZ)
+		priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET;
+
+	if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+		printk(KERN_ERR "%s arlan_command card busy end \n", dev->name);
+	priv->command_lock = 0;
+	ARLAN_DEBUG_EXIT("arlan_command");
+	return 1;
+
+bad_end:
+	printk(KERN_ERR "%s arlan_command bad end \n", dev->name);
+
+	priv->command_lock = 0;
+	ARLAN_DEBUG_EXIT("arlan_command");
+
+	return -1;
+
+command_busy_end:
+	if (arlan_debug & ARLAN_DEBUG_CARD_STATE)
+		printk(KERN_ERR "%s arlan_command command busy end \n", dev->name);
+	ARLAN_DEBUG_EXIT("arlan_command");
+	return 2;
+
+};
+
+extern inline void arlan_command_process(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	int times = 0;
+	while (priv->waiting_command_mask && times < 8)
+	{
+		if (priv->waiting_command_mask)
+		{
+			if (arlan_command(dev, 0))
+				break;
+			times++;
+		}
+		/* if long command, we wont repeat trying */ ;
+		if (priv->card_polling_interval > 1)
+			break;
+		times++;
+	}
+}
+
+
+extern inline void arlan_retransmit_now(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+
+	ARLAN_DEBUG_ENTRY("arlan_retransmit_now");
+	if (TXLAST(dev).offset == 0)
+	{
+		if (TXHEAD(dev).offset)
+		{
+			priv->txLast = 0;
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n");
+
+		}
+		else if (TXTAIL(dev).offset)
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n");
+			priv->txLast = 1;
+		}
+		else
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty");
+		priv->txOffset = 0;
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+		return;
+
+	}
+	arlan_command(dev, ARLAN_COMMAND_TX);
+
+	priv->nof_tx++;
+
+	priv->Conf->driverRetransmissions++;
+	priv->retransmissions++;
+
+	IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length);
+
+	ARLAN_DEBUG_EXIT("arlan_retransmit_now");
+}
+
+
+
+static void arlan_registration_timer(unsigned long data)
+{
+	struct device *dev = (struct device *) data;
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+
+	int lostTime = ((int) (jiffies - priv->registrationLastSeen)) * 1000 / HZ;
+	int bh_mark_needed = 0;
+	int next_tick = 1;
+
+
+	priv->timer_chain_active = 1;
+
+
+	if (registrationBad(dev))
+	{
+		//debug=100;
+		priv->registrationLostCount++;
+		if (lostTime > 7000 && lostTime < 7200)
+		{
+			printk(KERN_NOTICE "%s registration Lost \n", dev->name);
+		}
+		if (lostTime / priv->reRegisterExp > 2000)
+			arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF);
+		if (lostTime / (priv->reRegisterExp) > 3500)
+			arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+		if (priv->reRegisterExp < 400)
+			priv->reRegisterExp += 2;
+		if (lostTime > 7200)
+		{
+			next_tick = HZ;
+			arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+		}
+	}
+	else
+	{
+		if (priv->Conf->registrationMode && lostTime > 10000 &&
+			priv->registrationLostCount)
+		{
+			printk(KERN_NOTICE "%s registration is back after %d milliseconds\n", dev->name,
+				((int) (jiffies - priv->registrationLastSeen) * 1000) / HZ);
+		}
+		priv->registrationLastSeen = jiffies;
+		priv->registrationLostCount = 0;
+		priv->reRegisterExp = 1;
+		if (dev->start == 0)
+		{
+			dev->start = 1;
+			mark_bh(NET_BH);
+		}
+	}
+
+
+	if (!registrationBad(dev) && priv->ReTransmitRequested)
+	{
+		IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+			printk(KERN_ERR "Retranmit from timer \n");
+		priv->ReTransmitRequested = 0;
+		arlan_retransmit_now(dev);
+	}
+	if (!registrationBad(dev) &&
+		priv->tx_done_delayed < jiffies &&
+		priv->tx_done_delayed != 0)
+	{
+		TXLAST(dev).offset = 0;
+		if (priv->txLast)
+			priv->txLast = 0;
+		else if (TXTAIL(dev).offset)
+			priv->txLast = 1;
+		if (TXLAST(dev).offset)
+		{
+			arlan_retransmit_now(dev);
+			dev->trans_start = jiffies;
+		}
+		if (!(TXHEAD(dev).offset && TXTAIL(dev).offset))
+		{
+			priv->txOffset = 0;
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+		priv->tx_done_delayed = 0;
+		bh_mark_needed = 1;
+	}
+	if (bh_mark_needed)
+	{
+		priv->txOffset = 0;
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+	arlan_process_interrupt(dev);
+
+	if (next_tick < priv->card_polling_interval)
+		next_tick = priv->card_polling_interval;
+
+	priv->timer_chain_active = 0;
+	priv->timer.expires = jiffies + next_tick;
+
+	add_timer(&priv->timer);
+}
+
+
+
+
+static void arlan_print_registers(struct device *dev, int line)
+{
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+	u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage,
+		txStatus, rxStatus, interruptInProgress, commandByte;
+
+
+	ARLAN_DEBUG_ENTRY("arlan_print_registers");
+	READSHM(interruptInProgress, arlan->interruptInProgress, u_char);
+	READSHM(hostcpuLock, arlan->hostcpuLock, u_char);
+	READSHM(lancpuLock, arlan->lancpuLock, u_char);
+	READSHM(controlRegister, arlan->controlRegister, u_char);
+	READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char);
+	READSHM(txStatus, arlan->txStatus, u_char);
+	READSHM(rxStatus, arlan->rxStatus, u_char);
+	READSHM(commandByte, arlan->commandByte, u_char);
+
+	printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n",
+		line, interruptInProgress, hostcpuLock, lancpuLock, commandByte,
+		controlRegister, cntrlRegImage, txStatus, rxStatus);
+
+	ARLAN_DEBUG_EXIT("arlan_print_registers");
+}
+
+
+static int arlan_hw_tx(struct device *dev, char *buf, int length)
+{
+	int i;
+
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	volatile struct arlan_shmem *arlan = priv->card;
+	struct arlan_conf_stru *conf = priv->Conf;
+
+	int tailStarts = 0x800;
+	int headEnds = 0x0;
+
+
+	ARLAN_DEBUG_ENTRY("arlan_hw_tx");
+	if (TXHEAD(dev).offset)
+		headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 1) * 64;
+	if (TXTAIL(dev).offset)
+		tailStarts = 0x800 - (((TXTAIL(dev).offset - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 2) * 64;
+
+
+	if (!TXHEAD(dev).offset && length < tailStarts)
+	{
+		IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+			printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts);
+
+		TXHEAD(dev).offset =
+			(((int) arlan->txBuffer) - ((int) arlan));
+		TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN;
+		for (i = 0; i < 6; i++)
+			TXHEAD(dev).dest[i] = buf[i];
+		TXHEAD(dev).clear = conf->txClear;
+		TXHEAD(dev).retries = conf->txRetries;	/* 0 is use default */
+		TXHEAD(dev).routing = conf->txRouting;
+		TXHEAD(dev).scrambled = conf->txScrambled;
+		memcpy_toio(((char *) arlan + TXHEAD(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length);
+	}
+	else if (!TXTAIL(dev).offset && length < (0x800 - headEnds))
+	{
+		IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+			printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds);
+
+		TXTAIL(dev).offset =
+			(((int) arlan->txBuffer) - ((int) arlan)) + 0x800 - (length / 64 + 2) * 64;
+		TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN;
+		for (i = 0; i < 6; i++)
+			TXTAIL(dev).dest[i] = buf[i];
+		TXTAIL(dev).clear = conf->txClear;
+		TXTAIL(dev).retries = conf->txRetries;
+		TXTAIL(dev).routing = conf->txRouting;
+		TXTAIL(dev).scrambled = conf->txScrambled;
+		memcpy_toio(((char *) arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length);
+	}
+	else
+	{
+		dev->tbusy = 1;
+		return -1;
+		IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+			printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds);
+	}
+	priv->out_bytes += length;
+	priv->out_bytes10 += length;
+	if (conf->measure_rate < 1)
+		conf->measure_rate = 1;
+	if (jiffies - priv->out_time > conf->measure_rate * HZ)
+	{
+		conf->out_speed = priv->out_bytes / conf->measure_rate;
+		priv->out_bytes = 0;
+		priv->out_time = jiffies;
+	}
+	if (jiffies - priv->out_time10 > conf->measure_rate * HZ * 10)
+	{
+		conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate);
+		priv->out_bytes10 = 0;
+		priv->out_time10 = jiffies;
+	}
+	if (TXHEAD(dev).offset && TXTAIL(dev).offset)
+	{
+		dev->tbusy = 1;
+		return 0;
+	}
+	else
+		dev->tbusy = 0;
+
+
+	IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+		printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
+		   (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3],
+		   (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7],
+		   (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]);
+
+	IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast);
+
+	arlan_command(dev, ARLAN_COMMAND_TX);
+
+	priv->last_command_was_rx = 0;
+	priv->tx_last_sent = jiffies;
+	priv->nof_tx++;
+
+	IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length);
+
+	ARLAN_DEBUG_EXIT("arlan_hw_tx");
+
+	return 0;
+}
+
+
+static int arlan_hw_config(struct device *dev)
+{
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+
+	ARLAN_DEBUG_ENTRY("arlan_hw_config");
+
+	printk(KERN_NOTICE "%s arlan configure called \n", dev->name);
+	if (arlan_EEPROM_bad)
+		printk(KERN_NOTICE "arlan configure with eeprom bad option \n");
+
+
+	WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char);
+	WRITESHM(arlan->channelSet, conf->channelSet, u_char);
+
+	if (arlan_EEPROM_bad)
+		WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char);
+
+	WRITESHM(arlan->channelNumber, conf->channelNumber, u_char);
+
+	WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char);
+	WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char);
+
+	WRITESHM(arlan->systemId, conf->systemId, u_int);
+
+	WRITESHM(arlan->maxRetries, conf->maxRetries, u_char);
+	WRITESHM(arlan->receiveMode, conf->receiveMode, u_char);
+	WRITESHM(arlan->priority, conf->priority, u_char);
+	WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char);
+	WRITESHM(arlan->SID, conf->SID, u_int);
+
+	WRITESHM(arlan->registrationMode, conf->registrationMode, u_char);
+
+	WRITESHM(arlan->registrationFill, conf->registrationFill, u_char);
+	WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char);
+	WRITESHM(arlan->codeFormat, conf->codeFormat, u_char);
+	WRITESHM(arlan->numChannels, conf->numChannels, u_char);
+	WRITESHM(arlan->channel1, conf->channel1, u_char);
+	WRITESHM(arlan->channel2, conf->channel2, u_char);
+	WRITESHM(arlan->channel3, conf->channel3, u_char);
+	WRITESHM(arlan->channel4, conf->channel4, u_char);
+	WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short);
+	WRITESHM(arlan->SID, conf->SID, u_int);
+	WRITESHM(arlan->waitTime, conf->waitTime, u_short);
+	WRITESHM(arlan->lParameter, conf->lParameter, u_short);
+	memcpy_toio(&(arlan->_15), &(conf->_15), 3);
+	WRITESHM(arlan->_15, conf->_15, u_short);
+	WRITESHM(arlan->headerSize, conf->headerSize, u_short);
+	if (arlan_EEPROM_bad)
+		WRITESHM(arlan->hardwareType, conf->hardwareType, u_char);
+	WRITESHM(arlan->radioType, conf->radioType, u_char);
+	if (arlan_EEPROM_bad)
+		WRITESHM(arlan->radioModule, conf->radioType, u_char);
+
+	memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8);
+	memcpy_toio(arlan->name, conf->siteName, 16);
+
+	WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF);	/* do configure */
+	memset_io(arlan->commandParameter, 0, 0xf);	/* 0xf */
+	memset_io(arlan->commandParameter + 1, 0, 2);
+	if (conf->writeEEPROM)
+	{
+		  memset_io(arlan->commandParameter, conf->writeEEPROM, 1);
+//		conf->writeEEPROM=0;
+	}
+	if (conf->registrationMode && conf->registrationInterrupts)
+		memset_io(arlan->commandParameter + 3, 1, 1);
+	else
+		memset_io(arlan->commandParameter + 3, 0, 1);
+
+	priv->irq_test_done = 0;
+
+	if (conf->tx_queue_len)
+		dev->tx_queue_len = conf->tx_queue_len;
+	udelay(100);
+
+	ARLAN_DEBUG_EXIT("arlan_hw_config");
+	return 0;
+}
+
+
+static int arlan_read_card_configuration(struct device *dev)
+{
+	u_char tlx415;
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+
+	ARLAN_DEBUG_ENTRY("arlan_read_card_configuration");
+
+	if (radioNodeId == radioNodeIdUNKNOWN)
+	{
+		READSHM(conf->radioNodeId, arlan->radioNodeId, u_short);
+	}
+	else
+		conf->radioNodeId = radioNodeId;
+		
+	if (SID == SIDUNKNOWN)
+	{
+		READSHM(conf->SID, arlan->SID, u_int);
+	}
+	else conf->SID = SID;
+		
+	if (spreadingCode == spreadingCodeUNKNOWN)
+	{
+		  READSHM(conf->spreadingCode, arlan->spreadingCode, u_char);
+	}
+	else
+		conf->spreadingCode = spreadingCode;
+		
+	if (channelSet == channelSetUNKNOWN)
+	{
+		READSHM(conf->channelSet, arlan->channelSet, u_char);
+	}
+	else conf->channelSet = channelSet;
+
+	if (channelNumber == channelNumberUNKNOWN)
+	{
+		READSHM(conf->channelNumber, arlan->channelNumber, u_char);
+	}
+	else conf->channelNumber = channelNumber;
+	
+	READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char);
+	READSHM(conf->txAttenuation, arlan->txAttenuation, u_char);
+	
+	if (systemId == systemIdUNKNOWN)
+	{
+		READSHM(conf->systemId, arlan->systemId, u_int);
+	} 
+	else conf->systemId = systemId;
+	
+	READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short);
+	READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short);
+	READSHM(conf->maxRetries, arlan->maxRetries, u_char);
+	READSHM(conf->receiveMode, arlan->receiveMode, u_char);
+	READSHM(conf->priority, arlan->priority, u_char);
+	READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char);
+
+	if (SID == SIDUNKNOWN)
+	{
+		  READSHM(conf->SID, arlan->SID, u_int);
+	}
+	else conf->SID = SID;
+	
+	if (registrationMode == registrationModeUNKNOWN)
+	{
+		  READSHM(conf->registrationMode, arlan->registrationMode, u_char);
+	}
+	else conf->registrationMode = registrationMode;
+	
+	READSHM(conf->registrationFill, arlan->registrationFill, u_char);
+	READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char);
+	READSHM(conf->codeFormat, arlan->codeFormat, u_char);
+	READSHM(conf->numChannels, arlan->numChannels, u_char);
+	READSHM(conf->channel1, arlan->channel1, u_char);
+	READSHM(conf->channel2, arlan->channel2, u_char);
+	READSHM(conf->channel3, arlan->channel3, u_char);
+	READSHM(conf->channel4, arlan->channel4, u_char);
+	READSHM(conf->waitTime, arlan->waitTime, u_short);
+	READSHM(conf->lParameter, arlan->lParameter, u_short);
+	READSHM(conf->_15, arlan->_15, u_short);
+	READSHM(conf->headerSize, arlan->headerSize, u_short);
+	READSHM(conf->hardwareType, arlan->hardwareType, u_char);
+	READSHM(conf->radioType, arlan->radioModule, u_char);
+	
+	if (conf->radioType == 0)
+		conf->radioType = 0xc;
+
+	WRITESHM(arlan->configStatus, 0xA5, u_char);
+	READSHM(tlx415, arlan->configStatus, u_char);
+	
+	if (tlx415 != 0xA5)
+		printk(KERN_INFO "%s tlx415 chip \n", dev->name);
+	
+	conf->txClear = 0;
+	conf->txRetries = 1;
+	conf->txRouting = 1;
+	conf->txScrambled = 0;
+	conf->rxParameter = 1;
+	conf->txTimeoutMs = 4000;
+	conf->waitCardTimeout = 100000;
+	conf->receiveMode = ARLAN_RCV_CLEAN;
+	memcpy_fromio(conf->siteName, arlan->name, 16);
+	conf->siteName[16] = '\0';
+	conf->retries = retries;
+	conf->tx_delay_ms = tx_delay_ms;
+	conf->async = async;
+	conf->ReTransmitPacketMaxSize = 200;
+	conf->waitReTransmitPacketMaxSize = 200;
+	conf->txAckTimeoutMs = 900;
+	conf->fastReTransCount = 3;
+
+	ARLAN_DEBUG_EXIT("arlan_read_card_configuration");
+
+	return 0;
+}
+
+
+static int lastFoundAt = 0xbe000;
+
+
+/*
+ * This is the real probe routine. Linux has a history of friendly device
+ * probes on the ISA bus. A good device probes avoids doing writes, and
+ * verifies that the correct device exists and functions.
+ */
+
+__initfunctio(static int arlan_check_fingerprint(int memaddr))
+{
+	static char probeText[] = "TELESYSTEM SLW INC.    ARLAN \0";
+	char tempBuf[49];
+	volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr;
+
+	ARLAN_DEBUG_ENTRY("arlan_check_fingerprint");
+	memcpy_fromio(tempBuf, arlan->textRegion, 29);
+	tempBuf[30] = 0;
+
+	/* check for card at this address */
+	if (0 != strncmp(tempBuf, probeText, 29))
+		return -ENODEV;
+
+//   printk(KERN_INFO "arlan found at 0x%x \n",memaddr);
+	ARLAN_DEBUG_EXIT("arlan_check_fingerprint");
+
+	return 0;
+
+
+}
+
+__initfunctio(int arlan_probe_everywhere(struct device *dev))
+{
+	int m;
+	int probed = 0;
+	int found = 0;
+
+	ARLAN_DEBUG_ENTRY("arlan_probe_everywhere");
+	if (mem != 0 && numDevices == 1)	/* Check a single specified location. */
+	{
+		if (arlan_probe_here(dev, mem) == 0)
+			return 0;
+		else
+			return -ENODEV;
+	}
+	for (m = lastFoundAt + 0x2000; m <= 0xDE000; m += 0x2000)
+	{
+		if (arlan_probe_here(dev, m) == 0)
+		{
+			found++;
+			lastFoundAt = m;
+			break;
+		}
+		probed++;
+	}
+	if (found == 0 && probed != 0)
+	{
+		if (lastFoundAt == 0xbe000)
+			printk(KERN_ERR "arlan: No Arlan devices found \n");
+		return ENODEV;
+	}
+	else
+		return 0;
+
+	ARLAN_DEBUG_EXIT("arlan_probe_everywhere");
+
+	return ENODEV;
+}
+
+__initfunctio(int arlan_find_devices(void))
+{
+	int m;
+	int found = 0;
+
+	ARLAN_DEBUG_ENTRY("arlan_find_devices");
+	if (mem != 0 && numDevices == 1)	/* Check a single specified location. */
+		return 1;
+	for (m = 0xc000; m <= 0xDE000; m += 0x2000)
+	{
+		if (arlan_check_fingerprint(m) == 0)
+			found++;
+	}
+	ARLAN_DEBUG_EXIT("arlan_find_devices");
+
+	return found;
+}
+
+
+static int arlan_change_mtu(struct device *dev, int new_mtu)
+{
+	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+
+	ARLAN_DEBUG_ENTRY("arlan_change_mtu");
+	if ((new_mtu < 68) || (new_mtu > 2032))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	if (new_mtu < 256)
+		new_mtu = 256;	/* cards book suggests 1600 */
+	conf->maxDatagramSize = new_mtu;
+	conf->maxFrameSize = new_mtu + 48;
+
+	arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF);
+	printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu);
+
+	ARLAN_DEBUG_EXIT("arlan_change_mtu");
+
+	return 0;
+}
+
+static int arlan_mac_addr(struct device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+
+	ARLAN_DEBUG_ENTRY("arlan_mac_addr");
+	return -EINVAL;
+
+	if (dev->start)
+		return -EBUSY;
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	ARLAN_DEBUG_EXIT("arlan_mac_addr");
+	return 0;
+}
+
+
+
+
+__initfunctio(static int
+	      arlan_allocate_device(int num, struct device *devs))
+{
+
+	struct device *dev;
+
+	ARLAN_DEBUG_ENTRY("arlan_allocate_device");
+
+	if (!devs)
+		dev = init_etherdev(0, sizeof(struct arlan_private));
+	else
+	{
+		dev = devs;
+		dev->priv = kmalloc(sizeof(struct arlan_private), GFP_KERNEL);
+	};
+
+	if (dev == NULL || dev->priv == NULL)
+	{
+		printk(KERN_CRIT "init_etherdev failed ");
+		return 0;
+	}
+	((struct arlan_private *) dev->priv)->conf =
+	    kmalloc(sizeof(struct arlan_shmem), GFP_KERNEL);
+
+	if (dev == NULL || dev->priv == NULL ||
+	    ((struct arlan_private *) dev->priv)->conf == NULL)
+	{
+		return 0;
+		printk(KERN_CRIT " No memory at arlan_allocate_device \n");
+	}
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = 0;
+	dev->mem_start = 0;
+	dev->mem_end = 0;
+	dev->mtu = 1500;
+	dev->flags = 0;		/* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */
+	dev->irq = 0;
+	dev->dma = 0;
+	dev->tx_queue_len = tx_queue_len;
+	ether_setup(dev);
+	dev->tx_queue_len = tx_queue_len;
+	dev->open = arlan_open;
+	dev->stop = arlan_close;
+	dev->hard_start_xmit = arlan_tx;
+	dev->get_stats = arlan_statistics;
+	dev->set_multicast_list = arlan_set_multicast;
+	dev->change_mtu = arlan_change_mtu;
+	dev->set_mac_address = arlan_mac_addr;
+	((struct arlan_private *) dev->priv)->irq_test_done = 0;
+	arlan_device[num] = dev;
+	((struct arlan_private *) arlan_device[num]->priv)->Conf = &(arlan_conf[num]);
+
+	((struct arlan_private *) dev->priv)->Conf->pre_Command_Wait = 40;
+	((struct arlan_private *) dev->priv)->Conf->rx_tweak1 = 30;
+	((struct arlan_private *) dev->priv)->Conf->rx_tweak2 = 0;
+
+	ARLAN_DEBUG_EXIT("arlan_allocate_device");
+	return (int) dev;
+}
+
+
+__initfunctio(int arlan_probe_here(struct device *dev, int memaddr))
+{
+	volatile struct arlan_shmem *arlan;
+
+	ARLAN_DEBUG_ENTRY("arlan_probe_here");
+
+	if (arlan_check_fingerprint(memaddr))
+		return -ENODEV;
+
+	printk(KERN_NOTICE "%s: Arlan found at %#5x, \n ", dev->name, memaddr);
+
+	if (!arlan_allocate_device(arlans_found, dev))
+		return -1;
+
+	((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr;
+	arlan = (void *) memaddr;
+
+	dev->mem_start = memaddr;
+	dev->mem_end = memaddr + 0x1FFF;
+
+	if (dev->irq < 2)
+	{
+		READSHM(dev->irq, arlan->irqLevel, u_char);
+	} else if (dev->irq == 2)
+		dev->irq = 9;
+
+	arlan_read_card_configuration(dev);
+
+	ARLAN_DEBUG_EXIT("arlan_probe_here");
+	return 0;
+}
+
+
+
+
+static int arlan_open(struct device *dev)
+{
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	volatile struct arlan_shmem *arlan = priv->card;
+	int ret = 0;
+
+	ARLAN_DEBUG_ENTRY("arlan_open");
+
+	if (dev->mem_start == 0)
+		ret = arlan_probe_everywhere(dev);
+	if (ret != 0)
+		return ret;
+
+	arlan = ((struct arlan_private *) dev->priv)->card;
+
+	if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev))
+	{
+		printk(KERN_ERR "%s: unable to get IRQ %d .\n",
+			dev->name, dev->irq);
+		return -EAGAIN;
+	}
+	arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW);
+
+	priv->bad = 0;
+	priv->lastReset = 0;
+	priv->reset = 0;
+	priv->open_time = jiffies;
+	memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6);
+	memset(dev->broadcast, 0xff, 6);
+	dev->tbusy = 1;
+	priv->txOffset = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+	dev->tx_queue_len = tx_queue_len;
+	init_timer(&priv->timer);
+	priv->timer.expires = jiffies + HZ / 10;
+	priv->timer.data = (unsigned long) dev;
+	priv->timer.function = &arlan_registration_timer;	/* timer handler */
+	priv->interrupt_processing_active = 0;
+	priv->command_lock = 0;
+	add_timer(&priv->timer);
+
+	init_mutex(&priv->card_lock);
+	myATOMIC_INIT(priv->card_users, 1);	/* damn 2.0.33 */
+	priv->registrationLostCount = 0;
+	priv->registrationLastSeen = jiffies;
+	priv->txLast = 0;
+	priv->tx_command_given = 0;
+
+	priv->reRegisterExp = 1;
+	priv->nof_tx = 0;
+	priv->nof_tx_ack = 0;
+	priv->last_command_was_rx = 0;
+	priv->tx_last_sent = jiffies - 1;
+	priv->tx_last_cleared = jiffies;
+	priv->Conf->writeEEPROM = 0;
+	priv->Conf->registrationInterrupts = 1;
+
+	dev->tbusy = 0;
+
+	MOD_INC_USE_COUNT;
+#ifdef CONFIG_PROC_FS
+#ifndef MODULE
+	if (arlan_device[0])
+		init_arlan_proc();
+#endif
+#endif
+	ARLAN_DEBUG_EXIT("arlan_open");
+	return 0;
+}
+
+
+
+
+static int arlan_tx(struct sk_buff *skb, struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+
+	ARLAN_DEBUG_ENTRY("arlan_tx");
+
+	if (dev->tbusy)
+	{
+		/*
+		 * If we get here, some higher level has decided we are broken.
+		 * There should really be a "kick me" function call instead.
+		 */
+		int tickssofar = jiffies - dev->trans_start;
+
+		if (((tickssofar * 1000) / HZ) * 2 > conf->txTimeoutMs)
+			arlan_command(dev, ARLAN_COMMAND_TX_ABORT);
+
+		if (((tickssofar * 1000) / HZ) < conf->txTimeoutMs)
+		{
+			// up(&priv->card_lock);
+			goto bad_end;
+		}
+		printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name);
+		/* Try to restart the adaptor. */
+		arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+		dev->trans_start = jiffies;
+		goto bad_end;
+
+	}
+	/*
+	 * Block a timer-based transmit from overlapping. This could better be
+	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 */
+	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
+	{
+		printk(KERN_ERR "%s: Transmitter access conflict.\n",
+			dev->name);
+	}
+	else
+	{
+		short length;
+		unsigned char *buf;
+		
+		/*
+		 * If some higher layer thinks we've missed an tx-done interrupt
+		 * we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+		 * itself.
+		 */
+
+		length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		buf = skb->data;
+
+		if (priv->txOffset + length + 0x12 > 0x800)
+			printk(KERN_ERR "TX RING overflow \n");
+
+		if (arlan_hw_tx(dev, buf, length) == -1)
+			goto bad_end;
+
+		dev->trans_start = jiffies;
+	}
+	dev_kfree_skb(skb);
+
+	arlan_process_interrupt(dev);
+	priv->tx_chain_active = 0;
+	ARLAN_DEBUG_EXIT("arlan_tx");
+	return 0;
+
+bad_end:
+	arlan_process_interrupt(dev);
+	priv->tx_chain_active = 0;
+	ARLAN_DEBUG_EXIT("arlan_tx");
+	return 1;
+}
+
+
+extern inline int DoNotReTransmitCrap(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize)
+		return 1;
+	return 0;
+
+}
+
+extern inline int DoNotWaitReTransmitCrap(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize)
+		return 1;
+	return 0;
+}
+
+extern inline void arlan_queue_retransmit(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	ARLAN_DEBUG_ENTRY("arlan_queue_retransmit");
+
+	if (DoNotWaitReTransmitCrap(dev))
+	{
+		  arlan_drop_tx(dev);
+	} else
+		priv->ReTransmitRequested++;
+
+	ARLAN_DEBUG_EXIT("arlan_queue_retransmit");
+};
+
+extern inline void RetryOrFail(struct device *dev)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	ARLAN_DEBUG_ENTRY("RetryOrFail");
+
+	if (priv->retransmissions > priv->Conf->retries ||
+	    DoNotReTransmitCrap(dev))
+	{
+		arlan_drop_tx(dev);
+	}
+	else if (priv->bad <= priv->Conf->fastReTransCount)
+	{
+		arlan_retransmit_now(dev);
+	}
+	else arlan_queue_retransmit(dev);
+
+	ARLAN_DEBUG_EXIT("RetryOrFail");
+}
+
+
+static void arlan_tx_done_interrupt(struct device *dev, int status)
+{
+	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
+
+	ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt");
+
+	priv->tx_last_cleared = jiffies;
+	priv->tx_command_given = 0;
+	priv->nof_tx_ack++;
+	switch (status)
+	{
+		case 1:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit OK\n");
+			priv->stats.tx_packets++;
+			priv->bad = 0;
+			priv->reset = 0;
+			priv->retransmissions = 0;
+			if (priv->Conf->tx_delay_ms)
+			{
+				priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;;
+			}
+			else
+			{
+				TXLAST(dev).offset = 0;
+				if (priv->txLast)
+					priv->txLast = 0;
+				else if (TXTAIL(dev).offset)
+					priv->txLast = 1;
+				if (TXLAST(dev).offset)
+				{
+					arlan_retransmit_now(dev);
+					dev->trans_start = jiffies;
+				}
+				if (!TXHEAD(dev).offset || !TXTAIL(dev).offset)
+				{
+					priv->txOffset = 0;
+					dev->tbusy = 0;
+					mark_bh(NET_BH);
+				}
+			}
+		}
+		break;
+		
+		case 2:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit timed out\n");
+			priv->bad += 1;
+			//arlan_queue_retransmit(dev);
+			RetryOrFail(dev);
+		}
+		break;
+
+		case 3:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit max retries\n");
+			priv->bad += 1;
+			priv->reset = 0;
+			//arlan_queue_retransmit(dev);
+			RetryOrFail(dev);
+		}
+		break;
+		
+		case 4:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit aborted\n");
+			priv->bad += 1;
+			arlan_queue_retransmit(dev);
+			//RetryOrFail(dev);
+		}
+		break;
+
+		case 5:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit not registered\n");
+			priv->bad += 1;
+			//debug=101;
+			arlan_queue_retransmit(dev);
+		}
+		break;
+
+		case 6:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN) 
+				printk("arlan intr: transmit destination full\n");
+			priv->bad += 1;
+			priv->reset = 0;
+			//arlan_drop_tx(dev);
+			arlan_queue_retransmit(dev);
+		}
+		break;
+
+		case 7:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit unknown ack\n");
+			priv->bad += 1;
+			priv->reset = 0;
+			arlan_queue_retransmit(dev);
+		}
+		break;
+		
+		case 8:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit dest mail box full\n");
+			priv->bad += 1;
+			priv->reset = 0;
+			//arlan_drop_tx(dev);
+			arlan_queue_retransmit(dev);
+		}
+		break;
+
+		case 9:
+		{
+			IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
+				printk("arlan intr: transmit root dest not reg.\n");
+			priv->bad += 1;
+			priv->reset = 1;
+			//arlan_drop_tx(dev);
+			arlan_queue_retransmit(dev);
+		}
+		break;
+
+		default:
+		{
+			printk(KERN_ERR "arlan intr: transmit status unknown\n");
+			priv->bad += 1;
+			priv->reset = 1;
+			arlan_drop_tx(dev);
+		}
+	}
+
+	ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt");
+}
+
+
+static void arlan_rx_interrupt(struct device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len)
+{
+	char *skbtmp;
+	int i = 0;
+
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	volatile struct arlan_shmem *arlan = priv->card;
+	struct arlan_conf_stru *conf = priv->Conf;
+
+
+	ARLAN_DEBUG_ENTRY("arlan_rx_interrupt");
+	// by spec,   not                WRITESHMB(arlan->rxStatus,0x00);
+	// prohibited here              arlan_command(dev, ARLAN_COMMAND_RX);
+
+	if (pkt_len < 10 || pkt_len > 2048)
+	{
+		printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len);
+		return;
+	}
+	if (rxOffset + pkt_len > 0x2000)
+	{
+		printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset);
+		return;
+	}
+	priv->in_bytes += pkt_len;
+	priv->in_bytes10 += pkt_len;
+	if (conf->measure_rate < 1)
+		conf->measure_rate = 1;
+	if (jiffies - priv->in_time > conf->measure_rate * HZ)
+	{
+		conf->in_speed = priv->in_bytes / conf->measure_rate;
+		priv->in_bytes = 0;
+		priv->in_time = jiffies;
+	}
+	if (jiffies - priv->in_time10 > conf->measure_rate * HZ * 10)
+	{
+		conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate);
+		priv->in_bytes10 = 0;
+		priv->in_time10 = jiffies;
+	}
+	DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char);
+	switch (rxStatus)
+	{
+		case 1:
+		case 2:
+		case 3:
+		{
+			/* Malloc up new buffer. */
+			struct sk_buff *skb;
+
+			DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short);
+			DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char);
+			DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char);
+
+			/* here we do multicast filtering to avoid slow 8-bit memcopy */
+#ifdef ARLAN_MULTICAST
+			if (!(dev->flags & IFF_ALLMULTI) &&
+				!(dev->flags & IFF_PROMISC) &&
+				dev->mc_list)
+			{
+				char hw_dst_addr[6];
+				struct dev_mc_list *dmi = dev->mc_list;
+				int i;
+
+				memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6);
+				if (hw_dst_addr[0] == 0x01)
+				{
+					if (mdebug)
+						if (hw_dst_addr[1] == 0x00)
+							printk(KERN_ERR "%s mcast 0x0100 \n", dev->name);
+						else if (hw_dst_addr[1] == 0x40)
+							printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
+					while (dmi)
+					{							if (dmi->dmi_addrlen == 6)
+						{
+							if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
+								printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
+										 dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+										 dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+							for (i = 0; i < 6; i++)
+								if (dmi->dmi_addr[i] != hw_dst_addr[i])
+									break;
+							if (i == 6)
+								break;
+						}
+						else
+							printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name);
+						dmi = dmi->next;
+					}
+					/* we reach here if multicast filtering is on and packet 
+					 * is multicast and not for receive */
+					goto end_of_interupt;
+				}
+			}
+#endif				// ARLAN_MULTICAST
+			/* multicast filtering ends here */
+			pkt_len += ARLAN_FAKE_HDR_LEN;
+
+			skb = dev_alloc_skb(pkt_len + 4);
+			if (skb == NULL)
+			{
+				printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
+				priv->stats.rx_dropped++;
+				break;
+			}
+			skb_reserve(skb, 2);
+			skb->dev = dev;
+			skbtmp = skb_put(skb, pkt_len);
+
+			memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN);
+			memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6);
+			memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6);
+			WRITESHMB(arlan->rxStatus, 0x00);
+			arlan_command(dev, ARLAN_COMMAND_RX);
+
+			IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+			{
+				char immedDestAddress[6];
+				char immedSrcAddress[6];
+				memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
+				memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
+
+				printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name,
+					(unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3],
+					(unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7],
+					(unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11],
+					immedDestAddress[0], immedDestAddress[1], immedDestAddress[2],
+					immedDestAddress[3], immedDestAddress[4], immedDestAddress[5],
+					immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2],
+					immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]);
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+				if (skb->protocol != 0x608 && skb->protocol != 0x8)
+				{
+					for (i = 0; i <= 22; i++)
+						printk("%02x:", (u_char) skbtmp[i + 12]);
+					printk(KERN_ERR "\n");
+					printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol);
+				}
+			netif_rx(skb);
+			priv->stats.rx_packets++;
+		}
+		break;
+		
+		default:
+			printk(KERN_ERR "arlan intr: recieved unknown status\n");
+			priv->stats.rx_crc_errors++;
+			break;
+	}
+	ARLAN_DEBUG_EXIT("arlan_rx_interrupt");
+}
+
+static void arlan_process_interrupt(struct device *dev)
+{
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	volatile struct arlan_shmem *arlan = priv->card;
+	u_char rxStatus = READSHMB(arlan->rxStatus);
+	u_char txStatus = READSHMB(arlan->txStatus);
+	u_short rxOffset = READSHMS(arlan->rxOffset);
+	u_short pkt_len = READSHMS(arlan->rxLength);
+	int interrupt_count = 0;
+
+	ARLAN_DEBUG_ENTRY("arlan_process_interrupt");
+
+	if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active))
+	{
+		if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS)
+			printk(KERN_ERR "interrupt chain reentering \n");
+		goto end_int_process;
+	}
+	while ((rxStatus || txStatus || priv->interrupt_ack_requested)
+			&& (interrupt_count < 5))
+	{
+		if (rxStatus)
+			priv->last_rx_int_ack_time = arlan_time();
+
+		arlan_command(dev, ARLAN_COMMAND_INT_ACK);
+		arlan_command(dev, ARLAN_COMMAND_INT_ENABLE);
+		
+		IFDEBUG(ARLAN_DEBUG_INTERRUPT)
+			printk(KERN_ERR "%s:  got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n",
+					dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte),
+					rxOffset, pkt_len);
+
+		if (rxStatus == 0 && txStatus == 0)
+		{
+			priv->last_command_was_rx = 0;
+			if (priv->irq_test_done)
+			{
+				if (!registrationBad(dev))
+					IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ",
+										    dev->name, txStatus, rxStatus);
+			} else {
+				IFDEBUG(ARLAN_DEBUG_INTERRUPT)
+					printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq);
+
+			}
+			priv->interrupt_ack_requested = 0;
+			goto ends;
+		}
+		if (txStatus != 0)
+		{
+			WRITESHMB(arlan->txStatus, 0x00);
+			arlan_tx_done_interrupt(dev, txStatus);
+			goto ends;
+		}
+		if (rxStatus == 1 || rxStatus == 2)
+		{		/* a packet waiting */
+			arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len);
+			goto ends;
+		}
+		if (rxStatus > 2 && rxStatus < 0xff)
+		{
+			priv->last_command_was_rx = 0;
+			WRITESHMB(arlan->rxStatus, 0x00);
+			printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ",
+				dev->name, txStatus, rxStatus);
+			goto ends;
+		}
+		if (rxStatus == 0xff)
+		{
+			priv->last_command_was_rx = 0;
+			WRITESHMB(arlan->rxStatus, 0x00);
+			arlan_command(dev, ARLAN_COMMAND_RX);
+			if (registrationBad(dev))
+				dev->start = 0;
+			if (!registrationBad(dev))
+			{
+				priv->registrationLastSeen = jiffies;
+				if (!dev->tbusy && !priv->under_reset && !priv->under_config)
+				{
+					mark_bh(NET_BH);
+					dev->start = 1;
+				}
+			}
+			goto ends;
+		}
+ends:
+
+		arlan_command_process(dev);
+
+		rxStatus = READSHMB(arlan->rxStatus);
+		txStatus = READSHMB(arlan->txStatus);
+		rxOffset = READSHMS(arlan->rxOffset);
+		pkt_len = READSHMS(arlan->rxLength);
+
+
+		priv->irq_test_done = 1;
+
+		interrupt_count++;
+	}
+	priv->interrupt_processing_active = 0;
+
+end_int_process:
+	arlan_command_process(dev);
+
+	ARLAN_DEBUG_EXIT("arlan_process_interrupt");
+	return;
+}
+
+static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = dev_id;
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	volatile struct arlan_shmem *arlan = priv->card;
+	u_char rxStatus = READSHMB(arlan->rxStatus);
+	u_char txStatus = READSHMB(arlan->txStatus);
+
+	ARLAN_DEBUG_ENTRY("arlan_interrupt");
+
+
+	if (!rxStatus && !txStatus)
+		priv->interrupt_ack_requested++;
+	dev->interrupt++;
+
+	arlan_process_interrupt(dev);
+	
+	priv->irq_test_done = 1;
+	dev->interrupt--;
+
+	ARLAN_DEBUG_EXIT("arlan_interrupt");
+	return;
+
+}
+
+
+static int arlan_close(struct device *dev)
+{
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+
+	if (!dev)
+	{
+		printk(KERN_CRIT "arlan: No Device\n");
+		return 0;
+	}
+	priv = (struct arlan_private *) dev->priv;
+	if (!priv)
+	{
+		printk(KERN_CRIT "arlan: No Device priv \n");
+		return 0;
+	}
+	ARLAN_DEBUG_ENTRY("arlan_close");
+
+	IFDEBUG(ARLAN_DEBUG_STARTUP)
+		printk(KERN_NOTICE "%s: Closing device\n", dev->name);
+
+	priv->open_time = 0;
+	dev->tbusy = 1;
+	dev->start = 0;
+	del_timer(&priv->timer);
+	free_irq(dev->irq, dev);
+
+	MOD_DEC_USE_COUNT;
+
+	ARLAN_DEBUG_EXIT("arlan_close");
+	return 0;
+}
+
+
+static long alignLong(volatile u_char * ptr)
+{
+	long ret;
+	memcpy_fromio(&ret, (void *) ptr, 4);
+	return ret;
+}
+
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+
+static struct enet_statistics *arlan_statistics(struct device *dev)
+{
+	struct arlan_private *priv = (struct arlan_private *) dev->priv;
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+
+
+	ARLAN_DEBUG_ENTRY("arlan_statistics");
+
+	/* Update the statistics from the device registers. */
+
+	READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int);
+	READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
+	READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
+	READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
+	READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
+	READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int);
+	READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int);
+	READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
+	READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
+	READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
+	READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
+	READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
+	READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int);
+
+	ARLAN_DEBUG_EXIT("arlan_statistics");
+
+	return &priv->stats;
+}
+
+
+static void arlan_set_multicast(struct device *dev)
+{
+	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
+	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
+	int board_conf_needed = 0;
+
+
+	ARLAN_DEBUG_ENTRY("arlan_set_multicast");
+
+	if (dev->flags & IFF_PROMISC)
+	{
+		unsigned char recMode;
+		READSHM(recMode, arlan->receiveMode, u_char);
+		conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL);
+		if (conf->receiveMode != recMode)
+			board_conf_needed = 1;
+	}
+	else
+	{
+		/* turn off promiscuous mode  */
+		unsigned char recMode;
+		READSHM(recMode, arlan->receiveMode, u_char);
+		conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL;
+		if (conf->receiveMode != recMode)
+			board_conf_needed = 1;
+	}
+	if (board_conf_needed)
+		arlan_command(dev, ARLAN_COMMAND_CONF);
+
+	ARLAN_DEBUG_EXIT("arlan_set_multicast");
+}
+
+
+__initfunctio(int arlan_probe(struct device *dev))
+{
+	printk("Arlan driver %s\n", arlan_version);
+
+	if (arlan_probe_everywhere(dev))
+		return ENODEV;
+
+	arlans_found++;
+
+	if (arlans_found == 1)
+		siteName = kmalloc(100, GFP_KERNEL);
+	return 0;
+}
+
+#ifdef  MODULE
+
+int init_module(void)
+{
+	int i = 0;
+
+	ARLAN_DEBUG_ENTRY("init_module");
+
+	if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN)
+	{
+		printk(KERN_WARNING "arlan: wrong module params for multiple devices\n ");
+		return -1;
+	}
+	numDevices = arlan_find_devices();
+	if (numDevices == 0)
+	{
+		printk(KERN_ERR "arlan: no devices found \n");
+		return -1;
+	}
+
+	siteName = kmalloc(100, GFP_KERNEL);
+	if(siteName==NULL)
+	{
+		printk(KERN_ERR "arlan: No memory for site name.\n");
+		return -1;
+	}
+	for (i = 0; i < numDevices && i < MAX_ARLANS; i++)
+	{
+		if (!arlan_allocate_device(i, NULL))
+			return -1;
+		if (arlan_device[i] == NULL)
+		{
+			printk(KERN_CRIT "arlan: Not Enough memory \n");
+			return -1;
+		}
+		if (probe)
+			arlan_probe_everywhere(arlan_device[i]);
+	}
+	printk(KERN_INFO "Arlan driver %s\n", arlan_version);
+	ARLAN_DEBUG_EXIT("init_module");
+	return 0;
+}
+
+
+void cleanup_module(void)
+{
+	int i = 0;
+
+	ARLAN_DEBUG_ENTRY("cleanup_module");
+
+	IFDEBUG(ARLAN_DEBUG_SHUTDOWN)
+		printk(KERN_INFO "arlan: unloading module\n");
+	for (i = 0; i < MAX_ARLANS; i++)
+	{
+		if (arlan_device[i])
+		{
+			unregister_netdev(arlan_device[i]);
+			if (arlan_device[i]->priv)
+			{
+				if (((struct arlan_private *) arlan_device[i]->priv)->conf)
+					kfree(((struct arlan_private *) arlan_device[i]->priv)->conf);
+				kfree(arlan_device[i]);
+			}
+			arlan_device[i] = NULL;
+		}
+	}
+	ARLAN_DEBUG_EXIT("cleanup_module");
+}
+
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/net/arlan.h linux/drivers/net/arlan.h
--- v2.3.9/linux/drivers/net/arlan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/arlan.h	Mon Jul  5 20:09:40 1999
@@ -0,0 +1,574 @@
+/*
+ *  Copyright (C) 1997 Cullen Jennings
+ *  Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500	
+ *  Gnu Public License applies
+ */
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>	/* For the statistics structure. */
+#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+
+#define DEBUG 1
+
+#define ARLAN_PROC_INTERFACE
+#define MAX_ARLANS 4 /* not more than 4 ! */
+#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */
+
+#define ARLAN_MAX_MULTICAST_ADDRS 16
+#define ARLAN_RCV_CLEAN 	0
+#define ARLAN_RCV_PROMISC 1
+#define ARLAN_RCV_CONTROL 2
+
+
+#ifdef CONFIG_PROC_FS
+extern int 	init_arlan_proc(void);
+#endif
+
+extern struct device *arlan_device[MAX_ARLANS];
+static int	arlan_debug;
+static char *	siteName;
+static int	arlan_entry_debug;
+static int	arlan_exit_debug;
+static int	arlan_entry_and_exit_debug;
+static int	testMemory;
+static const char* arlan_version;
+ 
+#define SIDUNKNOWN -1
+#define radioNodeIdUNKNOWN -1
+#define encryptionKeyUNKNOWN '\0';
+#define irqUNKNOWN 0
+#define memUNKNOWN 0
+#define debugUNKNOWN 0
+#define probeUNKNOWN 1
+#define numDevicesUNKNOWN 1
+#define testMemoryUNKNOWN 1
+#define spreadingCodeUNKNOWN 0
+#define channelNumberUNKNOWN 0
+#define channelSetUNKNOWN 0
+#define systemIdUNKNOWN -1
+#define registrationModeUNKNOWN -1
+#define siteNameUNKNOWN "LinuxSite"
+
+
+
+#define IFDEBUG( L ) if ( (L) & arlan_debug ) 
+#define ARLAN_FAKE_HDR_LEN 12 
+
+#ifdef DEBUG
+	#define ARLAN_ENTRY_EXIT_DEBUGING 1
+	#define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b)
+#else
+	#define ARLAN_DEBUG(a,b) 
+#endif
+
+struct arlan_shmem
+{
+      /* Header Signature */ 
+      volatile	char textRegion[48];
+      volatile	u_char resetFlag;
+      volatile	u_char  diagnosticInfo;
+      volatile	u_short diagnosticOffset;
+      volatile	u_char _1[12];
+      volatile	u_char lanCardNodeId[6];
+      volatile	u_char broadcastAddress[6];
+      volatile	u_char hardwareType;
+      volatile	u_char majorHardwareVersion;
+      volatile	u_char minorHardwareVersion;
+      volatile	u_char radioModule;// shows EEPROM, can be overridden at 0x111
+      volatile	u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A
+      volatile	u_char _2[47];
+      
+      /* Control/Status Block - 0x0080 */
+      volatile	u_char interruptInProgress; /* not used by lancpu */
+      volatile	u_char cntrlRegImage; /* not used by lancpu */
+      volatile	u_char _3[13];
+      volatile	u_char dumpByte;
+      volatile	u_char commandByte; /* non-zero = active */
+      volatile	u_char commandParameter[15];
+
+      /* Receive Status - 0x00a0 */
+      volatile	u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */
+      volatile	u_char rxFrmType;
+      volatile	u_short rxOffset;
+      volatile	u_short rxLength;
+      volatile	u_char rxSrc[6];
+      volatile	u_char rxBroadcastFlag;
+      volatile	u_char rxQuality;
+      volatile	u_char scrambled;
+      volatile	u_char _4[1];
+      
+      /* Transmit Status - 0x00b0 */
+      volatile	u_char txStatus;
+      volatile	u_char txAckQuality;
+      volatile	u_char numRetries;
+      volatile	u_char _5[14];
+      volatile	u_char registeredRouter[6];
+      volatile	u_char backboneRouter[6];
+      volatile	u_char registrationStatus;
+      volatile	u_char configuredStatusFlag;
+      volatile	u_char _6[1];
+      volatile	u_char ultimateDestAddress[6];
+      volatile	u_char immedDestAddress[6];
+      volatile	u_char immedSrcAddress[6];
+      volatile	u_short rxSequenceNumber;
+      volatile	u_char assignedLocaltalkAddress;
+      volatile	u_char _7[27];
+
+      /* System Parameter Block */
+
+      /* - Driver Parameters (Novell Specific) */
+
+      volatile	u_short txTimeout;
+      volatile	u_short transportTime;
+      volatile	u_char _8[4];
+
+      /* - Configuration Parameters */
+      volatile	u_char irqLevel;
+      volatile	u_char spreadingCode;
+      volatile	u_char channelSet;
+      volatile	u_char channelNumber;
+      volatile	u_short radioNodeId;
+      volatile	u_char _9[2];
+      volatile	u_char scramblingDisable;
+      volatile	u_char radioType;
+      volatile	u_short routerId;
+      volatile	u_char _10[9];
+      volatile	u_char txAttenuation;
+      volatile	u_char systemId[4]; 
+      volatile	u_short globalChecksum;
+      volatile	u_char _11[4];
+      volatile	u_short maxDatagramSize;
+      volatile	u_short maxFrameSize;
+      volatile	u_char maxRetries;
+      volatile	u_char receiveMode;
+      volatile	u_char priority;
+      volatile	u_char rootOrRepeater;
+      volatile	u_char specifiedRouter[6];
+      volatile	u_short fastPollPeriod;
+      volatile	u_char pollDecay;
+      volatile	u_char fastPollDelay[2];
+      volatile	u_char arlThreshold;
+      volatile	u_char arlDecay;
+      volatile	u_char _12[1];
+      volatile	u_short specRouterTimeout;
+      volatile	u_char _13[5];
+
+      /* Scrambled Area */
+      volatile	u_char SID[4];
+      volatile	u_char encryptionKey[12];
+      volatile	u_char _14[2];
+      volatile	u_char waitTime[2];
+      volatile	u_char lParameter[2];
+      volatile	u_char _15[3];
+      volatile	u_short headerSize;
+      volatile	u_short sectionChecksum;
+
+      volatile	u_char registrationMode;
+      volatile	u_char registrationFill;
+      volatile	u_short pollPeriod;
+      volatile	u_short refreshPeriod;
+      volatile	u_char name[16];
+      volatile	u_char NID[6];
+      volatile	u_char localTalkAddress;
+      volatile	u_char codeFormat;
+      volatile	u_char numChannels;
+      volatile	u_char channel1;
+      volatile	u_char channel2;
+      volatile	u_char channel3;
+      volatile	u_char channel4;
+      volatile	u_char SSCode[59];
+
+      volatile	u_char _16[0xC0];
+      volatile	u_short auxCmd;
+      volatile	u_char  dumpPtr[4];
+      volatile	u_char dumpVal;
+      volatile	u_char _17[0x6A];
+      volatile	u_char wireTest;
+      volatile	u_char _18[14];
+
+      /* Statistics Block - 0x0300 */
+      volatile	u_char hostcpuLock;
+      volatile	u_char lancpuLock;
+      volatile	u_char resetTime[18];
+      
+      volatile	u_char numDatagramsTransmitted[4];
+      volatile	u_char numReTransmissions[4];
+      volatile	u_char numFramesDiscarded[4];
+      volatile	u_char numDatagramsReceived[4];
+      volatile	u_char numDuplicateReceivedFrames[4];
+      volatile	u_char numDatagramsDiscarded[4];
+      
+      volatile	u_short maxNumReTransmitDatagram;
+      volatile	u_short maxNumReTransmitFrames;
+      volatile	u_short maxNumConsecutiveDuplicateFrames;
+      /* misaligned here so we have to go to characters */
+     
+      volatile	u_char numBytesTransmitted[4];
+      volatile	u_char numBytesReceived[4];
+      volatile	u_char numCRCErrors[4];
+      volatile	u_char numLengthErrors[4];
+      volatile	u_char numAbortErrors[4];
+      volatile	u_char numTXUnderruns[4];
+      volatile	u_char numRXOverruns[4];
+      volatile	u_char numHoldOffs[4];
+      volatile	u_char numFramesTransmitted[4];
+      volatile	u_char numFramesReceived[4];
+      volatile	u_char numReceiveFramesLost[4];
+      volatile	u_char numRXBufferOverflows[4];
+      volatile	u_char numFramesDiscardedAddrMismatch[4];
+      volatile	u_char numFramesDiscardedSIDMismatch[4];
+      volatile	u_char numPollsTransmistted[4];
+      volatile	u_char numPollAcknowledges[4];
+      volatile	u_char numStatusTimeouts[4];
+      volatile	u_char numNACKReceived[4];
+
+      volatile	u_char _19[0x86];
+
+      volatile	u_char txBuffer[0x800];
+      volatile	u_char rxBuffer[0x800];
+
+      volatile	u_char _20[0x800];
+      volatile	u_char _21[0x3fb];
+      volatile	u_char configStatus;
+      volatile	u_char _22;
+      volatile	u_char progIOCtrl;
+      volatile	u_char shareMBase;
+      volatile	u_char controlRegister;
+};
+
+struct arlan_conf_stru {
+      int spreadingCode;
+      int channelSet;
+      int channelNumber;
+      int scramblingDisable;
+      int txAttenuation;
+      int systemId; 
+      int maxDatagramSize;
+      int maxFrameSize;
+      int maxRetries;
+      int receiveMode;
+      int priority;
+      int rootOrRepeater;
+      int SID;
+      int radioNodeId;
+      int registrationMode;
+      int registrationFill;
+      int localTalkAddress;
+      int codeFormat;
+      int numChannels;
+      int channel1;
+      int channel2;
+      int channel3;
+      int channel4;
+      int txClear;
+      int txRetries;
+      int txRouting;
+      int txScrambled;
+      int rxParameter;
+      int txTimeoutMs;
+      int txAckTimeoutMs;
+      int waitCardTimeout;
+      int	waitTime;
+      int	lParameter;
+      int	_15;
+      int	headerSize;
+      int async;
+      int retries;
+      int tx_delay_ms;
+      int waitReTransmitPacketMaxSize;
+      int ReTransmitPacketMaxSize;
+      int fastReTransCount;
+      int driverRetransmissions;
+      int registrationInterrupts;
+      int hardwareType;
+      int radioType;
+      int writeRadioType;
+      int writeEEPROM;
+      char siteName[17];
+      int measure_rate;
+      int in_speed;
+      int out_speed;
+      int in_speed10;
+      int out_speed10;
+      int in_speed_max;
+      int out_speed_max;
+      int pre_Command_Wait;
+      int rx_tweak1;
+      int rx_tweak2;
+      int tx_queue_len;
+};
+
+struct arlan_conf_stru arlan_conf[MAX_ARLANS];
+
+struct TxParam
+{
+      volatile	short 		offset;
+      volatile 	short 		length;
+      volatile	u_char 		dest[6];
+      volatile	unsigned	char clear;
+      volatile	unsigned	char retries;
+      volatile	unsigned	char routing;
+      volatile	unsigned	char scrambled;
+};
+
+struct TxRingPoint  {
+	struct TxParam txParam;
+	
+	
+};
+
+#define TX_RING_SIZE 2
+/* Information that need to be kept for each board. */
+struct arlan_private {
+      struct enet_statistics stats;
+      long open_time;			/* Useless example local info. */
+      struct arlan_shmem * card;
+      struct arlan_shmem * conf;
+      struct TxParam txParam;      
+      int multicastLength;
+      char  multicastList[ARLAN_MAX_MULTICAST_ADDRS][6];
+      int promiscModeEnabled;
+      struct arlan_conf_stru * Conf;	     
+      int	bad;
+      int 	reset;
+      long long lastReset;
+      struct timer_list timer;
+      struct timer_list tx_delay_timer;
+      struct timer_list tx_retry_timer;
+      struct timer_list rx_check_timer;
+      struct semaphore card_lock;
+      atomic_t 	card_users;
+      atomic_t	delay_on;
+      atomic_t  retr_on;
+      int registrationLostCount;
+      int reRegisterExp;
+      int nof_tx;
+      int nof_tx_ack;
+      int last_nof_tx;
+      int last_nof_tx_ack;
+      int irq_test_done;
+      int last_command_was_rx;
+      struct TxParam txRing[TX_RING_SIZE];
+      char reTransmitBuff[0x800];
+      volatile int txLast;
+      volatile int txNew;
+      volatile int txOffset;
+      volatile char ReTransmitRequested;
+      volatile long long tx_done_delayed;
+      volatile long long registrationLastSeen;
+      volatile char under_command;
+      volatile char under_toggle;
+      volatile long long tx_last_sent;
+      volatile long long tx_last_cleared;
+      volatile u_char under_tx;
+      volatile int 	retransmissions;
+      volatile int	tx_chain_active;
+      volatile int 	timer_chain_active;
+      volatile int 	interrupt_ack_requested;
+      volatile int	command_lock;
+      volatile int	rx_command_needed;
+      volatile int	tx_command_needed;
+      volatile int 	waiting_command_mask;
+      volatile int 	card_polling_interval;
+      volatile int 	last_command_buff_free_time;
+      volatile int	numResets;
+      volatile int 	under_reset;
+      volatile int 	under_config;
+      volatile int 	rx_command_given;
+      volatile int 	tx_command_given;
+      volatile int	interrupt_processing_active;
+      volatile long long 	last_tx_time;
+      volatile long long	last_rx_time;
+      volatile long long	last_rx_int_ack_time;
+      int	in_bytes;
+      int	out_bytes;
+      int	in_time;
+      int	out_time;
+      int	in_time10;
+      int	out_time10;
+      int	in_bytes10;
+      int	out_bytes10;
+};
+
+
+
+#define ARLAN_CLEAR		0x00
+#define ARLAN_RESET 		0x01
+#define ARLAN_CHANNEL_ATTENTION 0x02
+#define ARLAN_INTERRUPT_ENABLE 	0x04
+#define ARLAN_CLEAR_INTERRUPT 	0x08
+#define ARLAN_POWER 		0x40
+#define ARLAN_ACCESS		0x80
+
+#define ARLAN_COM_CONF                0x01
+#define ARLAN_COM_RX_ENABLE           0x03
+#define ARLAN_COM_RX_ABORT            0x04
+#define ARLAN_COM_TX_ENABLE           0x05
+#define ARLAN_COM_TX_ABORT            0x06
+#define ARLAN_COM_NOP		      0x07
+#define ARLAN_COM_STANDBY             0x08
+#define ARLAN_COM_ACTIVATE            0x09
+#define ARLAN_COM_GOTO_SLOW_POLL      0x0a
+#define ARLAN_COM_INT                 0x80
+
+
+#define TXLAST(dev) (((struct arlan_private *)dev->priv)->txRing[((struct arlan_private *)dev->priv)->txLast])
+#define TXHEAD(dev) (((struct arlan_private *)dev->priv)->txRing[0])
+#define TXTAIL(dev) (((struct arlan_private *)dev->priv)->txRing[1])
+
+#define TXBuffStart(dev) \
+ ((int)(((struct arlan_private *)dev->priv)->card)->txBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) )
+#define TXBuffEnd(dev) \
+ ((int)(((struct arlan_private *)dev->priv)->card)->rxBuffer) - ((int)(((struct arlan_private *)dev->priv)->card)
+ 
+#define READSHM(to,from,atype) {\
+	atype tmp;\
+	memcpy_fromio(&(tmp),&(from),sizeof(atype));\
+	to = tmp;\
+	}
+
+#define READSHMEM(from,atype)\
+	atype from; \
+	READSHM(from, arlan->from, atype);
+
+#define WRITESHM(to,from,atype) \
+	{ atype tmpSHM = from;\
+	memcpy_toio(&(to),&tmpSHM,sizeof(atype));\
+	}
+
+#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \
+	{	atype tmpSHM; \
+		memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\
+		IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\
+	}
+
+#define WRITESHMB(to, val) \
+	writeb(val,&(to))
+#define READSHMB(to) \
+	readb(&(to))
+#define WRITESHMS(to, val) \
+	writew(val,&(to))
+#define READSHMS(to) \
+	readw(&(to))
+#define WRITESHMI(to, val) \
+	writel(val,&(to))
+#define READSHMI(to) \
+	readl(&(to))
+
+
+
+
+
+#define registrationBad(dev)\
+   ( (   READSHMB(((struct arlan_private *)dev->priv)->card->registrationMode)    > 0) && \
+     (   READSHMB(((struct arlan_private *)dev->priv)->card->registrationStatus) == 0)    )
+
+
+#define readControlRegister(dev)\
+ 	READSHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage)
+
+#define writeControlRegister(dev, v){\
+   WRITESHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage	,((v) &0xF) );\
+   WRITESHMB(((struct arlan_private *)dev->priv)->card->controlRegister	,(v) 	);}
+
+
+#define arlan_interrupt_lancpu(dev) {\
+   int cr;   \
+   \
+   priv->under_toggle++;   \
+   cr = readControlRegister(dev);\
+   if (cr & ARLAN_CHANNEL_ATTENTION){ \
+      writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\
+   }else  \
+      writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\
+   priv->under_toggle=0;     \
+}
+
+#define clearChannelAttention(dev){ \
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);}
+#define setHardwareReset(dev) {\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);}
+#define clearHardwareReset(dev) {\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);}
+#define setInterruptEnable(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE)  ;}
+#define clearInterruptEnable(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE)  ;}
+#define setClearInterrupt(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT)   ;}
+#define clearClearInterrupt(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);}
+#define setPowerOff(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);}
+#define setPowerOn(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER));   }
+#define arlan_lock_card_access(dev){\
+   writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);}
+#define arlan_unlock_card_access(dev){\
+   writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); }  
+
+
+
+
+#define ARLAN_COMMAND_RX		0x00001
+#define ARLAN_COMMAND_NOOP		0x00002
+#define ARLAN_COMMAND_NOOPINT		0x00004
+#define ARLAN_COMMAND_TX		0x00008
+#define ARLAN_COMMAND_CONF		0x00010
+#define ARLAN_COMMAND_RESET		0x00020
+#define ARLAN_COMMAND_TX_ABORT		0x00040
+#define ARLAN_COMMAND_RX_ABORT		0x00080
+#define ARLAN_COMMAND_POWERDOWN		0x00100
+#define ARLAN_COMMAND_POWERUP		0x00200
+#define ARLAN_COMMAND_SLOW_POLL 	0x00400
+#define ARLAN_COMMAND_ACTIVATE 		0x00800
+#define ARLAN_COMMAND_INT_ACK		0x01000
+#define ARLAN_COMMAND_INT_ENABLE	0x02000
+#define ARLAN_COMMAND_WAIT_NOW		0x04000
+#define ARLAN_COMMAND_LONG_WAIT_NOW	0x08000
+#define ARLAN_COMMAND_STANDBY		0x10000
+#define ARLAN_COMMAND_INT_RACK		0x20000
+#define ARLAN_COMMAND_INT_RENABLE	0x40000
+#define ARLAN_COMMAND_CONF_WAIT		0x80000
+#define ARLAN_COMMAND_CLEAN_AND_CONF	(ARLAN_COMMAND_TX_ABORT\
+					| ARLAN_COMMAND_RX_ABORT\
+					| ARLAN_COMMAND_CONF)
+#define ARLAN_COMMAND_CLEAN_AND_RESET   (ARLAN_COMMAND_TX_ABORT\
+					| ARLAN_COMMAND_RX_ABORT\
+					| ARLAN_COMMAND_RESET)
+
+
+ 
+#define ARLAN_DEBUG_CHAIN_LOCKS		0x00001
+#define ARLAN_DEBUG_RESET		0x00002
+#define ARLAN_DEBUG_TIMING		0x00004
+#define ARLAN_DEBUG_CARD_STATE		0x00008
+#define ARLAN_DEBUG_TX_CHAIN		0x00010
+#define ARLAN_DEBUG_MULTICAST		0x00020
+#define ARLAN_DEBUG_HEADER_DUMP		0x00040
+#define ARLAN_DEBUG_INTERRUPT		0x00080
+#define ARLAN_DEBUG_STARTUP		0x00100
+#define ARLAN_DEBUG_SHUTDOWN		0x00200
+ 
\ No newline at end of file
diff -u --recursive --new-file v2.3.9/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.3.9/linux/drivers/net/atari_bionet.c	Sat Jun 13 13:28:34 1998
+++ linux/drivers/net/atari_bionet.c	Tue Jul  6 19:05:49 1999
@@ -324,8 +324,8 @@
 
 /* Check for a network adaptor of this type, and return '0' if one exists.
  */
-__initfunc(int
-bionet_probe(struct device *dev)) {
+int __init 
+bionet_probe(struct device *dev){
 	unsigned char station_addr[6];
 	static unsigned version_printed = 0;
 	static int no_more_found = 0; /* avoid "Probing for..." printed 4 times */
diff -u --recursive --new-file v2.3.9/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c
--- v2.3.9/linux/drivers/net/atari_pamsnet.c	Wed Oct  7 15:51:45 1998
+++ linux/drivers/net/atari_pamsnet.c	Tue Jul  6 19:05:49 1999
@@ -561,8 +561,8 @@
 /* Check for a network adaptor of this type, and return '0' if one exists.
  */
 
-__initfunc(extern int
-pamsnet_probe (dev))
+extern int __init 
+pamsnet_probe (dev)
 	struct device *dev;
 {
 	int i;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v2.3.9/linux/drivers/net/atarilance.c	Fri Feb 20 17:55:45 1998
+++ linux/drivers/net/atarilance.c	Tue Jul  6 19:05:49 1999
@@ -370,9 +370,9 @@
 }
 
 
-__initfunc(int atarilance_probe( struct device *dev ))
-
-{	int i;
+int __init atarilance_probe( struct device *dev )
+{	
+    int i;
 	static int found = 0;
 
 	if (!MACH_IS_ATARI || found)
@@ -393,9 +393,9 @@
 
 /* Derived from hwreg_present() in atari/config.c: */
 
-__initfunc(static int addr_accessible( volatile void *regp, int wordflag, int writeflag ))
-
-{	int		ret;
+static int __init addr_accessible( volatile void *regp, int wordflag, int writeflag )
+{
+	int		ret;
 	long	flags;
 	long	*vbr, save_berr;
 
@@ -443,10 +443,10 @@
 }
 
 
-__initfunc(static unsigned long lance_probe1( struct device *dev,
-								   struct lance_addr *init_rec ))
-
-{	volatile unsigned short *memaddr =
+static unsigned long __init lance_probe1( struct device *dev,
+								   struct lance_addr *init_rec )
+{
+	volatile unsigned short *memaddr =
 		(volatile unsigned short *)init_rec->memaddr;
 	volatile unsigned short *ioaddr =
 		(volatile unsigned short *)init_rec->ioaddr;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.3.9/linux/drivers/net/atp.c	Fri Nov 20 08:44:06 1998
+++ linux/drivers/net/atp.c	Tue Jul  6 19:05:49 1999
@@ -150,8 +150,8 @@
    If dev->base_addr == 2, allocate space for the device and return success
    (detachable devices only).
    */
-__initfunc(int
-atp_init(struct device *dev))
+int __init 
+atp_init(struct device *dev)
 {
 	int *port, ports[] = {0x378, 0x278, 0x3bc, 0};
 	int base_addr = dev->base_addr;
@@ -173,7 +173,7 @@
 	return ENODEV;
 }
 
-__initfunc(static int atp_probe1(struct device *dev, short ioaddr))
+static int __init atp_probe1(struct device *dev, short ioaddr)
 {
 	int saved_ctrl_reg, status;
 
@@ -259,7 +259,7 @@
 }
 
 /* Read the station address PROM, usually a word-wide EEPROM. */
-__initfunc(static void get_node_ID(struct device *dev))
+static void __init get_node_ID(struct device *dev)
 {
 	short ioaddr = dev->base_addr;
 	int sa_offset = 0;
@@ -291,7 +291,7 @@
  * DO :	 _________X_______X
  */
 
-__initfunc(static unsigned short eeprom_op(short ioaddr, unsigned int cmd))
+static unsigned short __init eeprom_op(short ioaddr, unsigned int cmd)
 {
 	unsigned eedata_out = 0;
 	int num_bits = EE_CMD_SIZE;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/com20020.c linux/drivers/net/com20020.c
--- v2.3.9/linux/drivers/net/com20020.c	Mon Sep 14 11:32:22 1998
+++ linux/drivers/net/com20020.c	Tue Jul  6 19:05:49 1999
@@ -96,7 +96,7 @@
 MODULE_PARM(backplane,"i");
 MODULE_PARM(clock,"i");
 #else
-__initfunc(void com20020_setup (char *str, int *ints));
+void __init com20020_setup (char *str, int *ints);
 extern struct device arcnet_devs[];
 extern char arcnet_dev_names[][10];
 extern int arcnet_num_devs;
@@ -224,7 +224,7 @@
  * it's where we were told it was, and even autoirq
  */
 
-__initfunc(int arc20020_probe(struct device *dev))
+int __init arc20020_probe(struct device *dev)
 {
   int ioaddr=dev->base_addr,status,delayval;
   unsigned long airqmask;
@@ -327,7 +327,7 @@
 /* Set up the struct device associated with this card.  Called after
  * probing succeeds.
  */
-__initfunc(int arc20020_found(struct device *dev,int ioaddr,int airq))
+int __init arc20020_found(struct device *dev,int ioaddr,int airq)
 {
   struct arcnet_local *lp;
   
@@ -1035,7 +1035,7 @@
 
 #else
 
-__initfunc(void com20020_setup (char *str, int *ints))
+void __init com20020_setup (char *str, int *ints)
 {
   struct device *dev;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/com90io.c linux/drivers/net/com90io.c
--- v2.3.9/linux/drivers/net/com90io.c	Mon Sep 14 11:32:22 1998
+++ linux/drivers/net/com90io.c	Tue Jul  6 19:05:49 1999
@@ -87,7 +87,7 @@
 MODULE_PARM(irq, "i");
 MODULE_PARM(device, "s");
 #else
-__initfunc(void com90io_setup (char *str, int *ints));
+void __init com90io_setup (char *str, int *ints);
 extern struct device arcnet_devs[];
 extern char arcnet_dev_names[][10];
 extern int arcnet_num_devs;
@@ -193,7 +193,7 @@
  * it's where we were told it was, and even autoirq
  */
 
-__initfunc(int arc90io_probe(struct device *dev))
+int __init arc90io_probe(struct device *dev)
 {
   int ioaddr=dev->base_addr,status,delayval;
   unsigned long airqmask;
@@ -287,7 +287,7 @@
 /* Set up the struct device associated with this card.  Called after
  * probing succeeds.
  */
-__initfunc(int arc90io_found(struct device *dev,int ioaddr,int airq))
+int __init arc90io_found(struct device *dev,int ioaddr,int airq)
 {
   struct arcnet_local *lp;
 
@@ -914,7 +914,7 @@
 
 #else
 
-__initfunc(void com90io_setup (char *str, int *ints))
+void __init com90io_setup (char *str, int *ints)
 {
   struct device *dev;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c
--- v2.3.9/linux/drivers/net/com90xx.c	Mon Sep 14 11:32:22 1998
+++ linux/drivers/net/com90xx.c	Tue Jul  6 19:05:49 1999
@@ -117,7 +117,7 @@
 MODULE_PARM(shmem, "i");
 MODULE_PARM(device, "s");
 #else
-__initfunc(void com90xx_setup(char *str, int *ints));
+void __init com90xx_setup(char *str, int *ints);
 char __initdata com90xx_explicit = 0;
 
 extern struct device arcnet_devs[];
@@ -179,7 +179,7 @@
 	0
 };
 
-__initfunc(int arc90xx_probe(struct device *dev))
+int __init arc90xx_probe(struct device *dev)
 {
 	static int init_once = 0;
 	static int numports = sizeof(ports) / sizeof(ports[0]), numshmems = sizeof(shmems) / sizeof(shmems[0]);
@@ -399,7 +399,7 @@
 			 */
 			airqmask = probe_irq_on();
 			AINTMASK(NORXflag);
-			udelay(1);
+			mdelay(1);
 			AINTMASK(0);
 			airq = probe_irq_off(airqmask);
 
@@ -493,7 +493,7 @@
 /* Set up the struct device associated with this card.  Called after
  * probing succeeds.
  */
-__initfunc(static int arc90xx_found(struct device *dev, int ioaddr, int airq, u_long shmem, int more))
+static int __init arc90xx_found(struct device *dev, int ioaddr, int airq, u_long shmem, int more)
 {
 	struct arcnet_local *lp;
 	u_long first_mirror, last_mirror;
@@ -1121,7 +1121,7 @@
 
 #else
 
-__initfunc(void com90xx_setup(char *str, int *ints))
+void __init com90xx_setup(char *str, int *ints)
 {
 	struct device *dev;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/cops.c linux/drivers/net/cops.c
--- v2.3.9/linux/drivers/net/cops.c	Wed Oct  7 15:51:45 1998
+++ linux/drivers/net/cops.c	Tue Jul  6 19:05:49 1999
@@ -218,7 +218,7 @@
  *      If dev->base_addr in [1..0x1ff], always return failure.
  *        otherwise go with what we pass in.
  */
-__initfunc(int cops_probe(struct device *dev))
+int __init cops_probe(struct device *dev)
 {
 	int i;
         int base_addr = dev ? dev->base_addr : 0;
@@ -252,7 +252,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 cops_probe1(struct device *dev, int ioaddr))
+static int __init cops_probe1(struct device *dev, int ioaddr)
 {
         struct cops_local *lp;
 	static unsigned version_printed = 0;
@@ -348,7 +348,7 @@
         return 0;
 }
 
-__initfunc(static int cops_irq (int ioaddr, int board))
+static int __init cops_irq (int ioaddr, int board)
 {       /*
          * This does not use the IRQ to determine where the IRQ is. We just
          * assume that when we get a correct status response that it's the IRQ.
diff -u --recursive --new-file v2.3.9/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
--- v2.3.9/linux/drivers/net/cosa.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/cosa.c	Tue Jul  6 19:05:49 1999
@@ -362,7 +362,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-__initfunc(static int cosa_init(void))
+static int __init cosa_init(void)
 #endif
 {
 	int i;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.3.9/linux/drivers/net/cs89x0.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/cs89x0.c	Tue Jul  6 19:05:49 1999
@@ -145,8 +145,8 @@
 struct netdev_entry netcard_drv =
 {"netcard", cs89x0_probe1, NETCARD_IO_EXTENT, netcard_portlist};
 #else
-__initfunc(int
-cs89x0_probe(struct device *dev))
+int __init 
+cs89x0_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -195,8 +195,8 @@
 	outw(value, dev->base_addr + portno);
 }
 
-__initfunc(static int
-wait_eeprom_ready(struct device *dev))
+static int __init 
+wait_eeprom_ready(struct device *dev)
 {
 	int timeout = jiffies;
 	/* check to see if the EEPROM is ready, a timeout is used -
@@ -208,8 +208,8 @@
 	return 0;
 }
 
-__initfunc(static int
-get_eeprom_data(struct device *dev, int off, int len, int *buffer))
+static int __init 
+get_eeprom_data(struct device *dev, int off, int len, int *buffer)
 {
 	int i;
 
@@ -226,8 +226,8 @@
         return 0;
 }
 
-__initfunc(static int
-get_eeprom_cksum(int off, int len, int *buffer))
+static int  __init 
+get_eeprom_cksum(int off, int len, int *buffer)
 {
 	int i, cksum;
 
@@ -244,7 +244,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 cs89x0_probe1(struct device *dev, int ioaddr))
+static int __init cs89x0_probe1(struct device *dev, int ioaddr)
 {
 	struct net_local *lp;
 	static unsigned version_printed = 0;
@@ -390,10 +390,8 @@
 	return 0;
 }
 
-
-
-__initfunc(void
-reset_chip(struct device *dev))
+void  __init 
+reset_chip(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.9/linux/drivers/net/de4x5.c	Sat May  8 19:46:44 1999
+++ linux/drivers/net/de4x5.c	Tue Jul  6 19:05:49 1999
@@ -1106,8 +1106,8 @@
 ** Autoprobing in modules is allowed here. See the top of the file for
 ** more info.
 */
-__initfunc(int
-de4x5_probe(struct device *dev))
+int __init 
+de4x5_probe(struct device *dev)
 {
     u_long iobase = dev->base_addr;
 
@@ -1121,8 +1121,8 @@
     return (dev->priv ? 0 : -ENODEV);
 }
 
-__initfunc(static int
-de4x5_hw_init(struct device *dev, u_long iobase))
+static int __init 
+de4x5_hw_init(struct device *dev, u_long iobase)
 {
     struct bus_type *lp = &bus;
     int i, status=0;
@@ -2054,8 +2054,8 @@
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-__initfunc(static void
-eisa_probe(struct device *dev, u_long ioaddr))
+static void __init 
+eisa_probe(struct device *dev, u_long ioaddr)
 {
     int i, maxSlots, status, device;
     u_char irq;
@@ -2136,8 +2136,8 @@
 */
 #define PCI_LAST_DEV  32
 
-__initfunc(static void
-pci_probe(struct device *dev, u_long ioaddr))
+static void __init 
+pci_probe(struct device *dev, u_long ioaddr)
 {
     u_char pb, pbus, dev_num, dnum, timer;
     u_short vendor, index, status;
@@ -2248,8 +2248,8 @@
 ** DECchips, we can find the base SROM irrespective of the BIOS scan direction.
 ** For single port cards this is a time waster...
 */
-__initfunc(static void
-srom_search(struct pci_dev *dev))
+static void __init 
+srom_search(struct pci_dev *dev)
 {
     u_char pb;
     u_short vendor, status;
@@ -2307,8 +2307,8 @@
     return;
 }
 
-__initfunc(static void
-link_modules(struct device *dev, struct device *tmp))
+static void __init 
+link_modules(struct device *dev, struct device *tmp)
 {
     struct device *p=dev;
 
@@ -5559,17 +5559,15 @@
     switch(ioc->cmd) {
     case DE4X5_GET_HWADDR:           /* Get the hardware address */
 	ioc->len = ETH_ALEN;
-	if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
 	for (i=0; i<ETH_ALEN; i++) {
 	    tmp.addr[i] = dev->dev_addr[i];
 	}
-	copy_to_user(ioc->data, tmp.addr, ioc->len);
+	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
 	break;
 
     case DE4X5_SET_HWADDR:           /* Set the hardware address */
 	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN)) return -EFAULT;
-	copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
+	if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT;
 	for (i=0; i<ETH_ALEN; i++) {
 	    dev->dev_addr[i] = tmp.addr[i];
 	}
@@ -5612,9 +5610,8 @@
 
     case DE4X5_GET_STATS:            /* Get the driver statistics */
 	ioc->len = sizeof(lp->pktStats);
-	if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
 	spin_lock_irqsave(&lp->lock, flags);
-	copy_to_user(ioc->data, &lp->pktStats, ioc->len); 
+	if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) return -EFAULT; 
 	spin_unlock_irqrestore(&lp->lock, flags);
 	break;
 
@@ -5627,14 +5624,12 @@
 
     case DE4X5_GET_OMR:              /* Get the OMR Register contents */
 	tmp.addr[0] = inl(DE4X5_OMR);
-	if (verify_area(VERIFY_WRITE, ioc->data, 1)) return -EFAULT;
-	copy_to_user(ioc->data, tmp.addr, 1);
+	if (copy_to_user(ioc->data, tmp.addr, 1)) return -EFAULT;
 	break;
 
     case DE4X5_SET_OMR:              /* Set the OMR Register contents */
 	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	if (verify_area(VERIFY_READ, ioc->data, 1)) return -EFAULT;
-	copy_from_user(tmp.addr, ioc->data, 1);
+	if (copy_from_user(tmp.addr, ioc->data, 1)) return -EFAULT;
 	outl(tmp.addr[0], DE4X5_OMR);
 	break;
 
@@ -5649,8 +5644,7 @@
 	tmp.lval[6] = inl(DE4X5_STRR); j+=4;
 	tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
 	ioc->len = j;
-	if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
-	copy_to_user(ioc->data, tmp.addr, ioc->len);
+	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
 	break;
 	
 #define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
@@ -5739,8 +5733,7 @@
 	tmp.addr[j++] = dev->tbusy;
 	
 	ioc->len = j;
-	if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
-	copy_to_user(ioc->data, tmp.addr, ioc->len);
+	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
 	break;
 
 */
@@ -5863,8 +5856,8 @@
 ** If at end of eth device list and can't use current entry, malloc
 ** one up. If memory could not be allocated, print an error message.
 */
-__initfunc(static struct device *
-insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
+static struct device * __init 
+insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))
 {
     struct device *new;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.3.9/linux/drivers/net/de600.c	Tue Feb 10 12:56:44 1998
+++ linux/drivers/net/de600.c	Tue Jul  6 19:05:49 1999
@@ -627,8 +627,8 @@
 	 */
 }
 
-__initfunc(int
-de600_probe(struct device *dev))
+int __init 
+de600_probe(struct device *dev)
 {
 	int	i;
 	static struct net_device_stats de600_netstats;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.3.9/linux/drivers/net/de620.c	Sat May 15 23:43:04 1999
+++ linux/drivers/net/de620.c	Tue Jul  6 19:05:49 1999
@@ -820,8 +820,8 @@
  *
  * Check if there is a DE-620 connected
  */
-__initfunc(int
-de620_probe(struct device *dev))
+int __init 
+de620_probe(struct device *dev)
 {
 	static struct net_device_stats de620_netstats;
 	int i;
@@ -913,8 +913,8 @@
  */
 #define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
 
-__initfunc(static unsigned short
-ReadAWord(struct device *dev, int from))
+static unsigned short __init 
+ReadAWord(struct device *dev, int from)
 {
 	unsigned short data;
 	int nbits;
@@ -956,8 +956,8 @@
 	return data;
 }
 
-__initfunc(static int
-read_eeprom(struct device *dev))
+static int __init 
+read_eeprom(struct device *dev)
 {
 	unsigned short wrd;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.3.9/linux/drivers/net/defxx.c	Fri Apr 16 13:58:46 1999
+++ linux/drivers/net/defxx.c	Tue Jul  6 19:05:49 1999
@@ -446,11 +446,8 @@
  *   the device structure.
  */
 
-__initfunc(int dfx_probe(
-	struct device *dev
-	))
-
-	{
+int __init dfx_probe(struct device *dev)
+{
 	int				i;				/* used in for loops */
 	int				version_disp;	/* was version info string already displayed? */
 	int				port_len;		/* length of port address range (in bytes) */
@@ -641,12 +638,8 @@
  *   None
  */
 
-__initfunc(struct device *dfx_alloc_device(
-	struct device	*dev,
-	u16				iobase
-	))
-
-	{
+struct device __init *dfx_alloc_device( struct device *dev, u16 iobase)
+{
 	struct device *tmp_dev;		/* pointer to a device structure */
 
 	DBG_printk("In dfx_alloc_device...\n");
@@ -736,11 +729,8 @@
  *   enabled yet.
  */
 
-__initfunc(void dfx_bus_init(
-	struct device *dev
-	))
-
-	{
+void __init dfx_bus_init(struct device *dev)
+{
 	DFX_board_t *bp = (DFX_board_t *)dev->priv;
 	u8			val;	/* used for I/O read/writes */
 
@@ -871,11 +861,8 @@
  *   None
  */
 
-__initfunc(void dfx_bus_config_check(
-	DFX_board_t *bp
-	))
-
-	{
+void __init dfx_bus_config_check(DFX_board_t *bp)
+{
 	int	status;				/* return code from adapter port control call */
 	u32	slot_id;			/* EISA-bus hardware id (DEC3001, DEC3002,...) */
 	u32	host_data;			/* LW data returned from port control call */
@@ -975,11 +962,8 @@
  *   returning from this routine.
  */
 
-__initfunc(int dfx_driver_init(
-	struct device *dev
-	))
-
-	{
+int __init dfx_driver_init(struct device *dev)
+{
 	DFX_board_t *bp = (DFX_board_t *)dev->priv;
 	int			alloc_size;			/* total buffer size needed */
 	char		*top_v, *curr_v;	/* virtual addrs into memory block */
diff -u --recursive --new-file v2.3.9/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.3.9/linux/drivers/net/depca.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/depca.c	Tue Jul  6 19:05:49 1999
@@ -476,10 +476,8 @@
     outw(CSR0, DEPCA_ADDR);\
     outw(STOP, DEPCA_DATA)
 
-
-
-__initfunc(int
-depca_probe(struct device *dev))
+int __init 
+depca_probe(struct device *dev)
 {
   int tmp = num_depcas, status = -ENODEV;
   u_long iobase = dev->base_addr;
@@ -512,8 +510,8 @@
   return status;
 }
 
-__initfunc(static int
-depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot))
+static int __init 
+depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot)
 {
   struct depca_private *lp;
   int i, j, offset, netRAM, mem_len, status=0;
@@ -1250,8 +1248,8 @@
 /*
 ** Microchannel bus I/O device probe
 */
-__initfunc(static void
-mca_probe(struct device *dev, u_long ioaddr))
+static void __init 
+mca_probe(struct device *dev, u_long ioaddr)
 {
     unsigned char pos[2];
     unsigned char where;
@@ -1399,8 +1397,8 @@
 /*
 ** ISA bus I/O device probe
 */
-__initfunc(static void
-isa_probe(struct device *dev, u_long ioaddr))
+static void __init 
+isa_probe(struct device *dev, u_long ioaddr)
 {
   int i = num_depcas, maxSlots;
   s32 ports[] = DEPCA_IO_PORTS;
@@ -1438,8 +1436,8 @@
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-__initfunc(static void
-eisa_probe(struct device *dev, u_long ioaddr))
+static void __init 
+eisa_probe(struct device *dev, u_long ioaddr)
 {
   int i, maxSlots;
   u_long iobase;
@@ -1485,8 +1483,8 @@
 ** are not available then insert a new device structure at the end of
 ** the current list.
 */
-__initfunc(static struct device *
-alloc_device(struct device *dev, u_long iobase))
+static struct device * __init 
+alloc_device(struct device *dev, u_long iobase)
 {
     struct device *adev = NULL;
     int fixed = 0, new_dev = 0;
@@ -1530,8 +1528,8 @@
 ** If at end of eth device list and can't use current entry, malloc
 ** one up. If memory could not be allocated, print an error message.
 */
-__initfunc(static struct device *
-insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
+static struct device * __init 
+insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))
 {
     struct device *new;
 
@@ -1556,8 +1554,8 @@
     return dev;
 }
 
-__initfunc(static int
-depca_dev_index(char *s))
+static int __init 
+depca_dev_index(char *s)
 {
     int i=0, j=0;
 
@@ -1576,8 +1574,8 @@
 ** and Boot (readb) ROM. This will also give us a clue to the network RAM
 ** base address.
 */
-__initfunc(static void
-DepcaSignature(char *name, u_long paddr))
+static void __init 
+DepcaSignature(char *name, u_long paddr)
 {
   u_int i,j,k;
   const char *signatures[] = DEPCA_SIGNATURE;
@@ -1629,8 +1627,8 @@
 ** PROM address counter is correctly positioned at the start of the
 ** ethernet address for later read out.
 */
-__initfunc(static int
-DevicePresent(u_long ioaddr))
+static int __init 
+DevicePresent(u_long ioaddr)
 {
   union {
     struct {
@@ -1682,8 +1680,8 @@
 ** reason: access the upper half of the PROM with x=0; access the lower half
 ** with x=1.
 */
-__initfunc(static int
-get_hw_addr(struct device *dev))
+static int __init 
+get_hw_addr(struct device *dev)
 {
   u_long ioaddr = dev->base_addr;
   int i, k, tmp, status = 0;
@@ -1771,8 +1769,8 @@
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-__initfunc(static int
-EISA_signature(char *name, s32 eisa_id))
+static int __init 
+EISA_signature(char *name, s32 eisa_id)
 {
   u_int i;
   const char *signatures[] = DEPCA_SIGNATURE;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.3.9/linux/drivers/net/dgrs.c	Tue Dec 29 11:32:06 1998
+++ linux/drivers/net/dgrs.c	Tue Jul  6 19:05:49 1999
@@ -991,8 +991,8 @@
 /*
  *	Download the board firmware
  */
-__initfunc(static int
-dgrs_download(struct device *dev0))
+static int __init 
+dgrs_download(struct device *dev0)
 {
 	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;
 	int		is;
@@ -1150,8 +1150,8 @@
 /*
  *	Probe (init) a board
  */
-__initfunc(int
-dgrs_probe1(struct device *dev))
+int __init 
+dgrs_probe1(struct device *dev)
 {
 	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
 	int		i;
@@ -1224,8 +1224,8 @@
 	return (0);
 }
 
-__initfunc(int
-dgrs_initclone(struct device *dev))
+int __init 
+dgrs_initclone(struct device *dev)
 {
 	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
 	int		i;
@@ -1239,7 +1239,7 @@
 	return (0);
 }
 
-__initfunc(static int
+static int __init 
 dgrs_found_device(
 	struct device	*dev,
 	int		io,
@@ -1247,7 +1247,7 @@
 	int		irq,
 	ulong		plxreg,
 	ulong		plxdma
-))
+)
 {
 	DGRS_PRIV	*priv;
 
@@ -1360,8 +1360,8 @@
  */
 static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
 
-__initfunc(static int
-dgrs_scan(struct device *dev))
+static int __init 
+dgrs_scan(struct device *dev)
 {
 	int	cards_found = 0;
 	uint	io;
@@ -1614,8 +1614,8 @@
 
 #else
 
-__initfunc(int
-dgrs_probe(struct device *dev))
+int __init 
+dgrs_probe(struct device *dev)
 {
 	int	cards_found;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v2.3.9/linux/drivers/net/dlci.c	Wed May  6 10:56:04 1998
+++ linux/drivers/net/dlci.c	Tue Jul  6 19:05:49 1999
@@ -601,7 +601,7 @@
 	return(0);
 }
 
-__initfunc(int dlci_setup(void))
+int __init dlci_setup(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v2.3.9/linux/drivers/net/dummy.c	Sun Oct  4 10:21:00 1998
+++ linux/drivers/net/dummy.c	Tue Jul  6 19:05:49 1999
@@ -80,7 +80,7 @@
 }
 #endif
 
-__initfunc(int dummy_init(struct device *dev))
+int __init dummy_init(struct device *dev)
 {
 	/* Initialize the device structure. */
 	dev->hard_start_xmit	= dummy_xmit;
@@ -127,7 +127,7 @@
 
 #ifdef MODULE
 
-__initfunc(static int dummy_probe(struct device *dev))
+static int __init dummy_probe(struct device *dev)
 {
 	dummy_init(dev);
 	return 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v2.3.9/linux/drivers/net/e2100.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/e2100.c	Tue Jul  6 19:05:49 1999
@@ -117,7 +117,7 @@
 	station address).
  */
 
-__initfunc(int e2100_probe(struct device *dev))
+int  __init e2100_probe(struct device *dev)
 {
 	int *port;
 	int base_addr = dev->base_addr;
@@ -137,7 +137,7 @@
 	return ENODEV;
 }
 
-__initfunc(int e21_probe1(struct device *dev, int ioaddr))
+int __init e21_probe1(struct device *dev, int ioaddr)
 {
 	int i, status;
 	unsigned char *station_addr = dev->dev_addr;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.9/linux/drivers/net/eepro100.c	Sat Feb  6 12:46:21 1999
+++ linux/drivers/net/eepro100.c	Mon Jul  5 20:09:40 1999
@@ -41,7 +41,7 @@
 static int max_interrupt_work = 200;
 
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
+static int multicast_filter_limit = 3;
 
 #include <linux/module.h>
 
@@ -343,7 +343,8 @@
 	const char *product_name;
 	struct device *next_module;
 	spinlock_t lock;
-	struct TxFD	tx_ring[TX_RING_SIZE];	/* Commands (usually CmdTxPacket). */
+	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 sk_buff* tx_skbuff[TX_RING_SIZE];
 	struct descriptor  *last_cmd;	/* Last command sent. */
diff -u --recursive --new-file v2.3.9/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.3.9/linux/drivers/net/eexpress.c	Sun May 30 10:18:49 1999
+++ linux/drivers/net/eexpress.c	Tue Jul  6 19:05:49 1999
@@ -325,7 +325,7 @@
  * checks for presence of EtherExpress card
  */
 
-__initfunc(int express_probe(struct device *dev))
+int __init express_probe(struct device *dev)
 {
 	unsigned short *port;
 	static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
@@ -961,7 +961,7 @@
  * than one card in a machine.
  */
 
-__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr))
+static int __init eexp_hw_probe(struct device *dev, unsigned short ioaddr)
 {
 	unsigned short hw_addr[3];
 	unsigned char buswidth;
@@ -1084,8 +1084,8 @@
  * Read a word from the EtherExpress on-board serial EEPROM.
  * The EEPROM contains 64 words of 16 bits.
  */
-__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
-						    unsigned char location))
+static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
+						    unsigned char location)
 {
 	unsigned short cmd = 0x180|(location&0x7f);
 	unsigned short rval = 0,wval = EC_CS|i586_RST;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.3.9/linux/drivers/net/eql.c	Mon May 10 13:00:10 1999
+++ linux/drivers/net/eql.c	Mon Jul  5 20:09:40 1999
@@ -209,7 +209,7 @@
    ---------------------------------------------------------
    */
 
-__initfunc(int eql_init(struct device *dev))
+int __init eql_init(struct device *dev)
 {
 	static unsigned version_printed = 0;
 	/* static unsigned num_masters     = 0; */
@@ -411,16 +411,15 @@
 	slaving_request_t srq;
 	int err;
 
-	err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t));
+	err = copy_from_user(&srq, srqp, sizeof (slaving_request_t));
 	if (err)  
 	  {
 #ifdef EQL_DEBUG
 	if (eql_debug >= 20)
-		printk ("EQL enslave: error detected by verify_area\n");
+		printk ("EQL enslave: error detected by copy_from_user\n");
 #endif  
 		return err;
 	  }
-	copy_from_user (&srq, srqp, sizeof (slaving_request_t));
 
 #ifdef EQL_DEBUG
 	if (eql_debug >= 20)
@@ -473,11 +472,10 @@
 	slaving_request_t srq;
 	int err;
 
-	err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t));
+	err = copy_from_user(&srq, srqp, sizeof (slaving_request_t));
 	if (err) 
 		return err;
 
-	copy_from_user (&srq, srqp, sizeof (slaving_request_t));
 #ifdef EQL_DEBUG
 	if (eql_debug >= 20)
 		printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name);
@@ -504,11 +502,10 @@
 	slave_config_t sc;
 	int err;
 
-	err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t));
+	err = copy_from_user (&sc, scp, sizeof (slave_config_t));
 	if (err) 
 		return err;
 
-	copy_from_user (&sc, scp, sizeof (slave_config_t));
 #ifdef EQL_DEBUG
 	if (eql_debug >= 20)
 		printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name);
@@ -541,7 +538,7 @@
 	slave_config_t sc;
 	int err;
 
-	err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t));
+	err = copy_from_user (&sc, scp, sizeof (slave_config_t));
 	if (err) 
 		return err;
 
@@ -550,7 +547,6 @@
 		printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name);
 #endif
   
-	copy_from_user (&sc, scp, sizeof (slave_config_t));
 
 	eql = (equalizer_t *) dev->priv;
 	slave_dev = dev_get (sc.slave_name);
@@ -583,13 +579,12 @@
 	if ( eql_is_master (dev) )
 	{
 		int err;
-		err = verify_area(VERIFY_WRITE, (void *)mcp, sizeof (master_config_t));
-		if (err) 
-			return err;
 		eql = (equalizer_t *) dev->priv;
 		mc.max_slaves = eql->max_slaves;
 		mc.min_slaves = eql->min_slaves;
-		copy_to_user (mcp, &mc, sizeof (master_config_t));
+		err = copy_to_user (mcp, &mc, sizeof (master_config_t));
+		if (err) 
+			return err;
 		return 0;
 	}
 	return -EINVAL;
@@ -602,14 +597,13 @@
 	master_config_t mc;
 	int err;
 
-	err = verify_area(VERIFY_READ, (void *)mcp, sizeof (master_config_t));
+	err = copy_from_user (&mc, mcp, sizeof (master_config_t));
 	if (err)
 		return err;
 #if EQL_DEBUG
 	if (eql_debug >= 20)
 		printk ("%s: set master config\n", dev->name);
 #endif
-	copy_from_user (&mc, mcp, sizeof (master_config_t));
 	if ( eql_is_master (dev) )
 	{
 		eql = (equalizer_t *) dev->priv;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/es3210.c linux/drivers/net/es3210.c
--- v2.3.9/linux/drivers/net/es3210.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/es3210.c	Tue Jul  6 19:05:49 1999
@@ -124,7 +124,7 @@
  *	PROM for a match against the Racal-Interlan assigned value.
  */
 
-__initfunc(int es_probe(struct device *dev))
+int __init es_probe(struct device *dev)
 {
 	unsigned short ioaddr = dev->base_addr;
 
@@ -151,7 +151,7 @@
 	return ENODEV;
 }
 
-__initfunc(int es_probe1(struct device *dev, int ioaddr))
+int __init es_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	unsigned long eisa_id;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.3.9/linux/drivers/net/eth16i.c	Thu Jan  7 08:46:59 1999
+++ linux/drivers/net/eth16i.c	Mon Jul  5 20:09:40 1999
@@ -450,7 +450,7 @@
 
 #else  /* Not HAVE_DEVLIST */
 
-__initfunc(int eth16i_probe(struct device *dev))
+int __init eth16i_probe(struct device *dev)
 {
 	int i;
 	int ioaddr;
@@ -484,7 +484,7 @@
 }
 #endif  /* Not HAVE_DEVLIST */
 
-__initfunc(static int eth16i_probe1(struct device *dev, int ioaddr))
+static int __init eth16i_probe1(struct device *dev, int ioaddr)
 {
 	static unsigned version_printed = 0;
 	boot = 1;  /* To inform initilization that we are in boot probe */
@@ -886,7 +886,7 @@
 	creg[0] &= 0x0F;      /* Mask collision cnr */
 	creg[2] &= 0x7F;      /* Mask DCLEN bit */
 
-#ifdef 0
+#if 0
 	/* 
 	   This was removed because the card was sometimes left to state
 	   from which it couldn't be find anymore. If there is need
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- v2.3.9/linux/drivers/net/ethertap.c	Tue May 11 08:24:31 1999
+++ linux/drivers/net/ethertap.c	Tue Jul  6 19:05:49 1999
@@ -65,7 +65,7 @@
  *	hardware it would have to check what was present.
  */
  
-__initfunc(int ethertap_probe(struct device *dev))
+int __init ethertap_probe(struct device *dev)
 {
 	memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6);
 	if (dev->mem_start & 0xf)
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.3.9/linux/drivers/net/ewrk3.c	Thu May 21 14:24:06 1998
+++ linux/drivers/net/ewrk3.c	Mon Jul  5 20:09:40 1999
@@ -342,11 +342,8 @@
     outb(EEPROM_INIT, EWRK3_IOPR);\
     mdelay(1);\
 }
-
-
-
 
-__initfunc(int ewrk3_probe(struct device *dev))
+int __init ewrk3_probe(struct device *dev)
 {
 	int tmp = num_ewrk3s, status = -ENODEV;
 	u_long iobase = dev->base_addr;
@@ -378,8 +375,8 @@
 	return status;
 }
 
-__initfunc(static int
-	   ewrk3_hw_init(struct device *dev, u_long iobase))
+static int __init 
+ewrk3_hw_init(struct device *dev, u_long iobase)
 {
 	struct ewrk3_private *lp;
 	int i, status = 0;
@@ -1285,7 +1282,7 @@
 /*
    ** ISA bus I/O device probe
  */
-__initfunc(static void isa_probe(struct device *dev, u_long ioaddr))
+static void __init isa_probe(struct device *dev, u_long ioaddr)
 {
 	int i = num_ewrk3s, maxSlots;
 	u_long iobase;
@@ -1325,7 +1322,7 @@
    ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
    ** the motherboard.
  */
-__initfunc(static void eisa_probe(struct device *dev, u_long ioaddr))
+static void __init eisa_probe(struct device *dev, u_long ioaddr)
 {
 	int i, maxSlots;
 	u_long iobase;
@@ -1372,8 +1369,8 @@
    ** are not available then insert a new device structure at the end of
    ** the current list.
  */
-__initfunc(static struct device *
-	   alloc_device(struct device *dev, u_long iobase))
+static struct device * __init 
+alloc_device(struct device *dev, u_long iobase)
 {
 	struct device *adev = NULL;
 	int fixed = 0, new_dev = 0;
@@ -1417,8 +1414,8 @@
    ** If at end of eth device list and can't use current entry, malloc
    ** one up. If memory could not be allocated, print an error message.
  */
-__initfunc(static struct device *
-	   insert_device(struct device *dev, u_long iobase, int (*init) (struct device *)))
+static __init struct device *
+insert_device(struct device *dev, u_long iobase, int (*init) (struct device *))
 {
 	struct device *new;
 
@@ -1443,8 +1440,8 @@
 	return dev;
 }
 
-__initfunc(static int
-	   ewrk3_dev_index(char *s))
+static int __init 
+ewrk3_dev_index(char *s)
 {
 	int i = 0, j = 0;
 
@@ -1499,7 +1496,7 @@
 /*
    ** Look for a particular board name in the on-board EEPROM.
  */
-__initfunc(static void EthwrkSignature(char *name, char *eeprom_image))
+static void __init EthwrkSignature(char *name, char *eeprom_image)
 {
 	u_long i, j, k;
 	char *signatures[] = EWRK3_SIGNATURE;
@@ -1536,7 +1533,7 @@
    ** ethernet address for later read out.
  */
 
-__initfunc(static int DevicePresent(u_long iobase))
+static int __init DevicePresent(u_long iobase)
 {
 	union {
 		struct {
@@ -1573,7 +1570,7 @@
 	return status;
 }
 
-__initfunc(static u_char get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType))
+static u_char __init get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType)
 {
 	int i, j, k;
 	u_short chksum;
@@ -1624,7 +1621,7 @@
 /*
    ** Look for a particular board name in the EISA configuration space
  */
-__initfunc(static int EISA_signature(char *name, s32 eisa_id))
+static int __init EISA_signature(char *name, s32 eisa_id)
 {
 	u_long i;
 	char *signatures[] = EWRK3_SIGNATURE;
@@ -1679,18 +1676,20 @@
 			tmp.addr[i] = dev->dev_addr[i];
 		}
 		ioc->len = ETH_ALEN;
-		if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) {
-			copy_to_user(ioc->data, tmp.addr, ioc->len);
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+			status = -EFAULT;
+			break;
 		}
-		break;
 	case EWRK3_SET_HWADDR:	/* Set the hardware address */
 		if (capable(CAP_NET_ADMIN)) {
-			if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) {
 				csr = inb(EWRK3_CSR);
 				csr |= (CSR_TXD | CSR_RXD);
 				outb(csr, EWRK3_CSR);	/* Disable the TX and RX */
 
-				copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
+				if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) {
+					status = -EFAULT;
+					break;
+				}
 				for (i = 0; i < ETH_ALEN; i++) {
 					dev->dev_addr[i] = tmp.addr[i];
 					outb(tmp.addr[i], EWRK3_PAR0 + i);
@@ -1698,7 +1697,6 @@
 
 				csr &= ~(CSR_TXD | CSR_RXD);	/* Enable the TX and RX */
 				outb(csr, EWRK3_CSR);
-			}
 		} else {
 			status = -EPERM;
 		}
@@ -1730,7 +1728,6 @@
 
 		break;
 	case EWRK3_GET_MCA:	/* Get the multicast address table */
-		if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
 			while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */
 			if (lp->shmem_length == IO_ONLY) {
 				outb(0, EWRK3_IOPR);
@@ -1743,17 +1740,21 @@
 				memcpy_fromio(tmp.addr, (char *) (lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3));
 			}
 			ioc->len = (HASH_TABLE_LEN >> 3);
-			copy_to_user(ioc->data, tmp.addr, ioc->len);
-		}
+			if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+				status = -EFAULT;
+				break;
+			}
+
 		lp->lock = 0;	/* Unlock the page register */
 
 		break;
 	case EWRK3_SET_MCA:	/* Set a multicast address */
 		if (capable(CAP_NET_ADMIN)) {
-			if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) {
-				copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
-				set_multicast_list(dev);
+			if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) {
+				status = -EFAULT;
+				break;
 			}
+			set_multicast_list(dev);
 		} else {
 			status = -EPERM;
 		}
@@ -1781,9 +1782,8 @@
 	case EWRK3_GET_STATS:	/* Get the driver statistics */
 		cli();
 		ioc->len = sizeof(lp->pktStats);
-		if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-			copy_to_user(ioc->data, &lp->pktStats, ioc->len);
-		}
+		if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
+			status = -EFAULT;
 		sti();
 
 		break;
@@ -1800,16 +1800,16 @@
 	case EWRK3_GET_CSR:	/* Get the CSR Register contents */
 		tmp.addr[0] = inb(EWRK3_CSR);
 		ioc->len = 1;
-		if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-			copy_to_user(ioc->data, tmp.addr, ioc->len);
-		}
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			status = -EFAULT;
 		break;
 	case EWRK3_SET_CSR:	/* Set the CSR Register contents */
 		if (capable(CAP_NET_ADMIN)) {
-			if (!(status = verify_area(VERIFY_READ, ioc->data, 1))) {
-				copy_from_user(tmp.addr, ioc->data, 1);
-				outb(tmp.addr[0], EWRK3_CSR);
+			if (copy_from_user(tmp.addr, ioc->data, 1)) {
+				status = -EFAULT;
+				break;
 			}
+			outb(tmp.addr[0], EWRK3_CSR);
 		} else {
 			status = -EPERM;
 		}
@@ -1826,9 +1826,8 @@
 				tmp.addr[i++] = inb(EWRK3_PAR0 + j);
 			}
 			ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
-			if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-				copy_to_user(ioc->data, tmp.addr, ioc->len);
-			}
+			if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+				status = -EFAULT;
 		} else {
 			status = -EPERM;
 		}
@@ -1836,11 +1835,12 @@
 		break;
 	case EWRK3_SET_EEPROM:	/* Set the EEPROM contents */
 		if (capable(CAP_NET_ADMIN)) {
-			if (!(status = verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) {
-				copy_from_user(tmp.addr, ioc->data, EEPROM_MAX);
-				for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-					Write_EEPROM(tmp.val[i], iobase, i);
-				}
+			if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) {
+				status = -EFAULT;
+				break;
+			}
+			for (i = 0; i < (EEPROM_MAX >> 1); i++) {
+				Write_EEPROM(tmp.val[i], iobase, i);
 			}
 		} else {
 			status = -EPERM;
@@ -1850,9 +1850,8 @@
 	case EWRK3_GET_CMR:	/* Get the CMR Register contents */
 		tmp.addr[0] = inb(EWRK3_CMR);
 		ioc->len = 1;
-		if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-			copy_to_user(ioc->data, tmp.addr, ioc->len);
-		}
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			status = -EFAULT;
 		break;
 	case EWRK3_SET_TX_CUT_THRU:	/* Set TX cut through mode */
 		if (suser()) {
diff -u --recursive --new-file v2.3.9/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.3.9/linux/drivers/net/fmv18x.c	Tue Jan 19 10:13:13 1999
+++ linux/drivers/net/fmv18x.c	Tue Jul  6 19:05:49 1999
@@ -132,8 +132,8 @@
 struct netdev_entry fmv18x_drv =
 {"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};
 #else
-__initfunc(int
-fmv18x_probe(struct device *dev))
+int __init 
+fmv18x_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -163,7 +163,7 @@
    that can be done is checking a few bits and then diving right into MAC
    address check. */
 
-__initfunc(int fmv18x_probe1(struct device *dev, short ioaddr))
+int __init fmv18x_probe1(struct device *dev, short ioaddr)
 {
 	char irqmap[4] = {3, 7, 10, 15};
 	char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- v2.3.9/linux/drivers/net/hamradio/6pack.c	Fri Nov 20 08:44:06 1998
+++ linux/drivers/net/hamradio/6pack.c	Tue Jul  6 19:05:49 1999
@@ -726,7 +726,7 @@
 #ifdef MODULE
 static int sixpack_init_ctrl_dev(void)
 #else	/* !MODULE */
-__initfunc(int sixpack_init_ctrl_dev(struct device *dummy))
+int __init sixpack_init_ctrl_dev(struct device *dummy)
 #endif	/* !MODULE */
 {
 	int status;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c
--- v2.3.9/linux/drivers/net/hamradio/baycom_par.c	Fri Oct  9 12:20:27 1998
+++ linux/drivers/net/hamradio/baycom_par.c	Tue Jul  6 19:05:49 1999
@@ -533,7 +533,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int baycom_par_init(void))
+int __init baycom_par_init(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -593,7 +593,7 @@
 
 #endif
 
-__initfunc(int init_module(void))
+int __init init_module(void)
 {
 	int i;
 
@@ -633,7 +633,7 @@
  * mode: par96,picpar
  */
 
-__initfunc(void baycom_par_setup(char *str, int *ints))
+void __init baycom_par_setup(char *str, int *ints)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c
--- v2.3.9/linux/drivers/net/hamradio/baycom_ser_fdx.c	Sun Jan 17 18:28:06 1999
+++ linux/drivers/net/hamradio/baycom_ser_fdx.c	Tue Jul  6 19:05:49 1999
@@ -605,7 +605,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int baycom_ser_fdx_init(void))
+int __init baycom_ser_fdx_init(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -673,7 +673,7 @@
 
 #endif
 
-__initfunc(int init_module(void))
+int __init init_module(void)
 {
 	int i;
 
@@ -716,7 +716,7 @@
  * * indicates sofware DCD
  */
 
-__initfunc(void baycom_ser_fdx_setup(char *str, int *ints))
+void __init baycom_ser_fdx_setup(char *str, int *ints)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c
--- v2.3.9/linux/drivers/net/hamradio/baycom_ser_hdx.c	Sun Jan 17 18:28:06 1999
+++ linux/drivers/net/hamradio/baycom_ser_hdx.c	Tue Jul  6 19:05:49 1999
@@ -643,7 +643,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int baycom_ser_hdx_init(void))
+int __init baycom_ser_hdx_init(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -707,7 +707,7 @@
 
 #endif
 
-__initfunc(int init_module(void))
+int __init init_module(void)
 {
 	int i;
 
@@ -749,7 +749,7 @@
  * * indicates sofware DCD
  */
 
-__initfunc(void baycom_ser_hdx_setup(char *str, int *ints))
+void __init baycom_ser_hdx_setup(char *str, int *ints)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- v2.3.9/linux/drivers/net/hamradio/bpqether.c	Tue May 25 13:06:34 1999
+++ linux/drivers/net/hamradio/bpqether.c	Tue Jul  6 19:05:49 1999
@@ -621,7 +621,7 @@
  * Initialize driver. To be called from af_ax25 if not compiled as a
  * module
  */
-__initfunc(int bpq_init(void))
+int __init bpq_init(void)
 {
 	struct device *dev;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.3.9/linux/drivers/net/hamradio/dmascc.c	Fri Oct  9 11:56:59 1998
+++ linux/drivers/net/hamradio/dmascc.c	Tue Jul  6 19:05:49 1999
@@ -336,7 +336,7 @@
 #else
 
 
-__initfunc(void dmascc_setup(char *str, int *ints))
+void __init dmascc_setup(char *str, int *ints)
 {
    int i;
 
@@ -350,7 +350,7 @@
 
 /* Initialization functions */
 
-__initfunc(int dmascc_init(void))
+int __init dmascc_init(void)
 {
   int h, i, j, n;
   int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS],
@@ -453,8 +453,7 @@
   return -EIO;
 }
 
-
-__initfunc(int setup_adapter(int io, int h, int n))
+int __init setup_adapter(int io, int h, int n)
 {
   int i, irq, chip;
   struct scc_info *info;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c
--- v2.3.9/linux/drivers/net/hamradio/hdlcdrv.c	Tue Dec 29 11:30:56 1998
+++ linux/drivers/net/hamradio/hdlcdrv.c	Tue Jul  6 19:05:49 1999
@@ -43,7 +43,6 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/in.h>
@@ -936,7 +935,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int init_module(void))
+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");
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- v2.3.9/linux/drivers/net/hamradio/mkiss.c	Fri Nov 13 10:29:44 1998
+++ linux/drivers/net/hamradio/mkiss.c	Tue Jul  6 19:05:50 1999
@@ -937,7 +937,7 @@
 }
 
 /* Initialize AX25 control device -- register AX25 line discipline */
-__initfunc(int mkiss_init_ctrl_dev(void))
+int __init mkiss_init_ctrl_dev(void)
 {
 	int status;
 
@@ -1154,7 +1154,7 @@
 /* * 			Init MKISS driver 			      * */
 /* ******************************************************************** */
 
-__initfunc(static int mkiss_init(void))
+static int __init mkiss_init(void)
 {
 	memset(&mkiss_driver, 0, sizeof(struct tty_driver));
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/pi2.c linux/drivers/net/hamradio/pi2.c
--- v2.3.9/linux/drivers/net/hamradio/pi2.c	Tue Feb 10 13:07:50 1998
+++ linux/drivers/net/hamradio/pi2.c	Tue Jul  6 19:05:50 1999
@@ -927,7 +927,7 @@
 /* Probe for a PI card. */
 /* This routine also initializes the timer chip */
 
-__initfunc(static int hw_probe(int ioaddr))
+static int __init hw_probe(int ioaddr)
 {
     int time = 1000;		/* Number of milliseconds for test */
     unsigned long start_time, end_time;
@@ -1182,7 +1182,7 @@
 }
 
 
-__initfunc(int pi_init(void))
+int __init pi_init(void)
 {
     int *port;
     int ioaddr = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/pt.c linux/drivers/net/hamradio/pt.c
--- v2.3.9/linux/drivers/net/hamradio/pt.c	Tue Feb 10 13:07:50 1998
+++ linux/drivers/net/hamradio/pt.c	Tue Jul  6 19:05:50 1999
@@ -474,8 +474,7 @@
 } /* chipset_init() */
 
 
-
-__initfunc(int pt_init(void))
+int __init pt_init(void)
 {
     int *port;
     int ioaddr = 0;
@@ -537,7 +536,7 @@
 /*
  * Probe for PT card.  Also initialises the timers
  */
-__initfunc(static int hw_probe(int ioaddr))
+static int __init hw_probe(int ioaddr)
 {
     int time = 1000;		/* Number of milliseconds to test */
     int a = 1;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.3.9/linux/drivers/net/hamradio/scc.c	Fri Dec 18 13:57:21 1998
+++ linux/drivers/net/hamradio/scc.c	Tue Jul  6 19:05:50 1999
@@ -2193,7 +2193,7 @@
 /* * 			Init SCC driver 			      * */
 /* ******************************************************************** */
 
-__initfunc(int scc_init (void))
+int __init scc_init (void)
 {
 	int chip, chan, k, result;
 	char devname[10];
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c
--- v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.c	Sun Jan 17 18:28:06 1999
+++ linux/drivers/net/hamradio/soundmodem/sm.c	Tue Jul  6 19:05:50 1999
@@ -640,9 +640,9 @@
 /* --------------------------------------------------------------------- */
 
 #ifdef MODULE
-__initfunc(static int sm_init(void))
+static int __init sm_init(void)
 #else /* MODULE */
-__initfunc(int sm_init(void))
+int __init sm_init(void)
 #endif /* MODULE */
 {
 	int i, j, found = 0;
@@ -724,7 +724,7 @@
 
 #endif
 
-__initfunc(int init_module(void))
+int __init init_module(void)
 {
 	if (mode) {
 		if (iobase == -1)
@@ -778,7 +778,7 @@
  * modem: afsk1200, fsk9600
  */
 
-__initfunc(void sm_setup(char *str, int *ints))
+void __init sm_setup(char *str, int *ints)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.h linux/drivers/net/hamradio/soundmodem/sm.h
--- v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.h	Fri Jul 10 14:01:13 1998
+++ linux/drivers/net/hamradio/soundmodem/sm.h	Mon Jul  5 20:35:18 1999
@@ -296,8 +296,6 @@
 
 #ifdef __i386__
 
-#include <asm/processor.h>
-
 #define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC)
 
 /*
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c
--- v2.3.9/linux/drivers/net/hostess_sv11.c	Thu Feb 18 16:28:49 1999
+++ linux/drivers/net/hostess_sv11.c	Mon Jul  5 20:09:40 1999
@@ -389,7 +389,8 @@
 	free_irq(dev->sync.irq, dev);
 	if(dma)
 	{
-		free_dma(dev->sync.chanA.rxdma);
+		if(dma==1)
+			free_dma(dev->sync.chanA.rxdma);
 		free_dma(dev->sync.chanA.txdma);
 	}
 	release_region(dev->sync.chanA.ctrlio-1, 8);
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v2.3.9/linux/drivers/net/hp-plus.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/hp-plus.c	Tue Jul  6 19:05:50 1999
@@ -123,7 +123,7 @@
 {"hpplus", hpp_probe1, HP_IO_EXTENT, hpplus_portlist};
 #else
 
-__initfunc(int hp_plus_probe(struct device *dev))
+int __init hp_plus_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -146,7 +146,7 @@
 #endif
 
 /* Do the interesting part of the probe at a single address. */
-__initfunc(int hpp_probe1(struct device *dev, int ioaddr))
+int __init hpp_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	unsigned char checksum = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v2.3.9/linux/drivers/net/hp.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/hp.c	Tue Jul  6 19:05:50 1999
@@ -84,7 +84,7 @@
 {"hp", hp_probe1, HP_IO_EXTENT, hppclan_portlist};
 #else
 
-__initfunc(int hp_probe(struct device *dev))
+int __init hp_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -106,7 +106,7 @@
 }
 #endif
 
-__initfunc(int hp_probe1(struct device *dev, int ioaddr))
+int __init hp_probe1(struct device *dev, int ioaddr)
 {
 	int i, board_id, wordmode;
 	const char *name;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.3.9/linux/drivers/net/hp100.c	Mon Jan 11 10:55:29 1999
+++ linux/drivers/net/hp100.c	Tue Jul  6 19:05:50 1999
@@ -106,6 +106,7 @@
 #include <linux/types.h>
 #include <linux/config.h>  /* for CONFIG_PCI */
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #define LINUX_2_1
@@ -347,7 +348,7 @@
  *  since this could cause problems when the card is not installed.
  */
  
-__initfunc(int hp100_probe( struct device *dev ))
+int __init hp100_probe( struct device *dev )
 {
   int base_addr = dev ? dev -> base_addr : 0;
   int ioaddr = 0;
@@ -524,9 +525,9 @@
 
 
 #ifdef LINUX_2_1
-__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev ))
+static int __init hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev )
 #else
-__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ))
+static int __init hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )
 #endif
 {
   int i;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hplance.c linux/drivers/net/hplance.c
--- v2.3.9/linux/drivers/net/hplance.c	Thu Jun 25 11:03:42 1998
+++ linux/drivers/net/hplance.c	Tue Jul  6 19:05:50 1999
@@ -67,7 +67,7 @@
 #endif
 
 /* Find all the HP Lance boards and initialise them... */
-__initfunc(int hplance_probe(struct device *dev))
+int __init hplance_probe(struct device *dev)
 {
         int cards = 0, called = 0;
 
@@ -98,7 +98,7 @@
 }
 
 /* Initialise a single lance board at the given select code */
-__initfunc (static int hplance_init(struct device *dev, int scode))
+static int __init hplance_init(struct device *dev, int scode)
 {
         /* const char *name = dio_scodetoname(scode); */
         static const char name[] = "HP LANCE";
diff -u --recursive --new-file v2.3.9/linux/drivers/net/hydra.c linux/drivers/net/hydra.c
--- v2.3.9/linux/drivers/net/hydra.c	Tue Feb 10 12:56:44 1998
+++ linux/drivers/net/hydra.c	Tue Jul  6 19:05:50 1999
@@ -157,7 +157,7 @@
 
 #endif
 
-__initfunc(int hydra_probe(struct device *dev))
+int __init hydra_probe(struct device *dev)
 {
 	struct hydra_private *priv;
 	u32 board;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.3.9/linux/drivers/net/ibmtr.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/net/ibmtr.c	Tue Jul  6 19:05:50 1999
@@ -138,11 +138,9 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
-#include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
@@ -173,7 +171,7 @@
 	"ISA", "MCA", "ISA P&P" 
 };
 
-__initfunc(char *adapter_def(char type))
+char __init *adapter_def(char type)
 {
 	switch (type) 
 	{
@@ -223,7 +221,7 @@
 
 static __u32 ibmtr_mem_base = 0xd0000;
 
-__initfunc(static void PrtChanID(char *pcid, short stride) )
+static void __init PrtChanID(char *pcid, short stride) 
 {
 	short i, j;
 	for (i=0, j=0; i<24; i++, j+=stride)
@@ -231,7 +229,7 @@
 	printk("\n");
 }
 
-__initfunc(static void HWPrtChanID (__u32 pcid, short stride))
+static void __init HWPrtChanID (__u32 pcid, short stride)
 {
 	short i, j;
 	for (i=0, j=0; i<24; i++, j+=stride)
@@ -252,7 +250,7 @@
  *	which references it.
  */
  
-__initfunc(int ibmtr_probe(struct device *dev))
+int __init ibmtr_probe(struct device *dev)
 {
         int i;
         int base_addr = dev ? dev->base_addr : 0;
@@ -295,7 +293,7 @@
         return -ENODEV;
 }
 
-__initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
+static int __init ibmtr_probe1(struct device *dev, int PIOaddr)
 {
 	unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0;
 	__u32 t_mmio=0;
@@ -750,7 +748,7 @@
 
 /* query the adapter for the size of shared RAM  */
 
-__initfunc(static unsigned char get_sram_size(struct tok_info *adapt_info))
+static unsigned char __init get_sram_size(struct tok_info *adapt_info)
 {
 
 	unsigned char avail_sram_code;
@@ -769,7 +767,7 @@
 		return 1<<((readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4);
 }
 
-__initfunc(static int trdev_init(struct device *dev))
+static int __init trdev_init(struct device *dev)
 {
 	struct tok_info *ti=(struct tok_info *)dev->priv;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/actisys.c linux/drivers/net/irda/actisys.c
--- v2.3.9/linux/drivers/net/irda/actisys.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/actisys.c	Tue Jul  6 19:05:49 1999
@@ -61,7 +61,7 @@
 	actisys_init_qos,
 };
 
-__initfunc(int actisys_init(void))
+int __init actisys_init(void)
 {
 	int ret;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/esi.c linux/drivers/net/irda/esi.c
--- v2.3.9/linux/drivers/net/irda/esi.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/esi.c	Tue Jul  6 19:05:49 1999
@@ -52,7 +52,7 @@
 	esi_qos_init,
 };
 
-__initfunc(int esi_init(void))
+int __init esi_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/girbil.c linux/drivers/net/irda/girbil.c
--- v2.3.9/linux/drivers/net/irda/girbil.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/girbil.c	Tue Jul  6 19:05:49 1999
@@ -76,7 +76,7 @@
 	girbil_init_qos,
 };
 
-__initfunc(int girbil_init(void))
+int __init girbil_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- v2.3.9/linux/drivers/net/irda/irport.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/net/irda/irport.c	Tue Jul  6 19:05:49 1999
@@ -86,7 +86,7 @@
 static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
 static int  irport_raw_write(struct irda_device *idev, __u8 *buf, int len);
 
-__initfunc(int irport_init(void))
+int __init irport_init(void)
 {
  	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.3.9/linux/drivers/net/irda/irtty.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/irda/irtty.c	Tue Jul  6 19:05:49 1999
@@ -64,7 +64,7 @@
 			      char *, int);
 char *driver_name = "irtty";
 
-__initfunc(int irtty_init(void))
+int __init irtty_init(void)
 {
 	int status;
 	
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/litelink.c linux/drivers/net/irda/litelink.c
--- v2.3.9/linux/drivers/net/irda/litelink.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/litelink.c	Tue Jul  6 19:05:49 1999
@@ -60,7 +60,7 @@
 	litelink_init_qos,
 };
 
-__initfunc(int litelink_init(void))
+int __init litelink_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c
--- v2.3.9/linux/drivers/net/irda/pc87108.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/pc87108.c	Tue Jul  6 19:05:49 1999
@@ -127,7 +127,7 @@
  *    Initialize chip. Just try to find out how many chips we are dealing with
  *    and where they are
  */
-__initfunc(int pc87108_init(void))
+int __init pc87108_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- v2.3.9/linux/drivers/net/irda/smc-ircc.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/smc-ircc.c	Tue Jul  6 19:05:49 1999
@@ -33,8 +33,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -102,7 +100,7 @@
  *    Initialize chip. Just try to find out how many chips we are dealing with
  *    and where they are
  */
-__initfunc(int ircc_init(void))
+int __init ircc_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/tekram.c linux/drivers/net/irda/tekram.c
--- v2.3.9/linux/drivers/net/irda/tekram.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/tekram.c	Tue Jul  6 19:05:49 1999
@@ -56,7 +56,7 @@
 	tekram_init_qos,
 };
 
-__initfunc(int tekram_init(void))
+int __init tekram_init(void)
 {
 	return irda_device_register_dongle(&dongle);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.3.9/linux/drivers/net/irda/toshoboe.c	Sun May 30 10:27:04 1999
+++ linux/drivers/net/irda/toshoboe.c	Mon Jul  5 20:09:40 1999
@@ -568,11 +568,11 @@
   self->rxs = inb_p (OBOE_RCVT);
   self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET;
 
-#ifdef 0
+#if 0
   self->rxs = 0;
   self->txs = 0;
 #endif
-#ifdef 0
+#if 0
   self->rxs = RX_SLOTS - 1;
   self->txs = 0;
 #endif
@@ -838,7 +838,7 @@
   return (0);
 }
 
-__initfunc (int toshoboe_init (void))
+int __init toshoboe_init (void)
 {
   struct pci_dev *pci_dev = NULL;
   int found = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/uircc.c linux/drivers/net/irda/uircc.c
--- v2.3.9/linux/drivers/net/irda/uircc.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/uircc.c	Tue Jul  6 19:05:49 1999
@@ -36,8 +36,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -90,7 +88,7 @@
  *    Initialize chip. Just try to find out how many chips we are dealing with
  *    and where they are
  */
-__initfunc(int uircc_init(void))
+int __init uircc_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- v2.3.9/linux/drivers/net/irda/w83977af_ir.c	Mon Jun  7 16:18:58 1999
+++ linux/drivers/net/irda/w83977af_ir.c	Tue Jul  6 19:05:49 1999
@@ -105,7 +105,7 @@
  *    Initialize chip. Just try to find out how many chips we are dealing with
  *    and where they are
  */
-__initfunc(int w83977af_init(void))
+int __init w83977af_init(void)
 {
         int i;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.3.9/linux/drivers/net/lance.c	Mon Dec 28 11:05:14 1998
+++ linux/drivers/net/lance.c	Tue Jul  6 19:05:49 1999
@@ -420,7 +420,7 @@
 	return -ENODEV;
 }
 
-__initfunc(int lance_probe1(struct device *dev, int ioaddr, int irq, int options))
+int __init lance_probe1(struct device *dev, int ioaddr, int irq, int options)
 {
 	struct lance_private *lp;
 	short dma_channels;					/* Mark spuriously-busy DMA channels */
@@ -499,6 +499,8 @@
 		
 	lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
 										   GFP_DMA | GFP_KERNEL)+7) & ~7);
+	if(lp==NULL)
+		return -ENODEV;
 	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
 	memset(lp, 0, sizeof(*lp));
 	dev->priv = lp;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/lne390.c linux/drivers/net/lne390.c
--- v2.3.9/linux/drivers/net/lne390.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/lne390.c	Tue Jul  6 19:08:33 1999
@@ -100,7 +100,7 @@
  *	PROM for a match against the value assigned to Mylex.
  */
 
-__initfunc(int lne390_probe(struct device *dev))
+int __init lne390_probe(struct device *dev)
 {
 	unsigned short ioaddr = dev->base_addr;
 
@@ -127,7 +127,7 @@
 	return ENODEV;
 }
 
-__initfunc(int lne390_probe1(struct device *dev, int ioaddr))
+int __init lne390_probe1(struct device *dev, int ioaddr)
 {
 	int i, revision;
 	unsigned long eisa_id;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.3.9/linux/drivers/net/loopback.c	Thu Jun 11 22:52:33 1998
+++ linux/drivers/net/loopback.c	Tue Jul  6 19:08:33 1999
@@ -114,7 +114,7 @@
 }
 
 /* Initialize the rest of the LOOPBACK device. */
-__initfunc(int loopback_init(struct device *dev))
+int __init loopback_init(struct device *dev)
 {
 	dev->mtu		= LOOPBACK_MTU;
 	dev->tbusy		= 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
--- v2.3.9/linux/drivers/net/ltpc.c	Fri Jan 15 14:36:21 1999
+++ linux/drivers/net/ltpc.c	Tue Jul  6 19:08:33 1999
@@ -1018,7 +1018,7 @@
 
 /* initialization stuff */
   
-__initfunc(int ltpc_probe_dma(int base))
+int __init ltpc_probe_dma(int base)
 {
 	int dma = 0;
   	int timeout;
@@ -1088,7 +1088,7 @@
 	return dma;
 }
 
-__initfunc(int ltpc_probe(struct device *dev))
+int __init ltpc_probe(struct device *dev)
 {
 	int err;
 	int x=0,y=0;
@@ -1250,7 +1250,7 @@
 }
 
 /* handles "ltpc=io,irq,dma" kernel command lines */
-__initfunc(void ltpc_setup(char *str, int *ints))
+void __init ltpc_setup(char *str, int *ints)
 {
 	if (ints[0] == 0) {
 		if (str && !strncmp(str, "auto", 4)) {
diff -u --recursive --new-file v2.3.9/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.3.9/linux/drivers/net/myri_sbus.c	Wed Jun  9 14:45:36 1999
+++ linux/drivers/net/myri_sbus.c	Tue Jul  6 19:08:33 1999
@@ -1074,7 +1074,7 @@
 	return 0;
 }
 
-__initfunc(int myri_sbus_probe(struct device *dev))
+int __init myri_sbus_probe(struct device *dev)
 {
 	struct linux_sbus *bus;
 	struct linux_sbus_device *sdev = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.3.9/linux/drivers/net/ne.c	Sun Mar  7 15:47:46 1999
+++ linux/drivers/net/ne.c	Tue Jul  6 19:08:33 1999
@@ -177,7 +177,7 @@
  * the card.
  */
 
-__initfunc(int ne_probe(struct device *dev))
+int __init ne_probe(struct device *dev)
 {
 	int base_addr = dev ? dev->base_addr : 0;
 
@@ -209,7 +209,7 @@
 #endif
 
 #ifdef CONFIG_PCI
-__initfunc(static int ne_probe_pci(struct device *dev))
+static int __init ne_probe_pci(struct device *dev)
 {
 	int i;
 
@@ -243,7 +243,7 @@
 }
 #endif  /* CONFIG_PCI */
 
-__initfunc(static int ne_probe1(struct device *dev, int ioaddr))
+static int __init ne_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	unsigned char SA_prom[32];
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne2.c linux/drivers/net/ne2.c
--- v2.3.9/linux/drivers/net/ne2.c	Wed Mar 10 16:51:35 1999
+++ linux/drivers/net/ne2.c	Tue Jul  6 19:08:33 1999
@@ -146,7 +146,7 @@
  * Note that at boot, this probe only picks up one card at a time.
  */
 
-__initfunc (int ne2_probe(struct device *dev))
+int __init ne2_probe(struct device *dev)
 {
 	static int current_mca_slot = -1;
 	int i;
@@ -198,8 +198,7 @@
 	return len;
 }
 
-
-__initfunc (static int ne2_probe1(struct device *dev, int slot))
+static int __init ne2_probe1(struct device *dev, int slot)
 {
 	int i, base_addr, irq;
 	unsigned char POS;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.3.9/linux/drivers/net/ne2k-pci.c	Sun Jan 24 22:04:02 1999
+++ linux/drivers/net/ne2k-pci.c	Mon Jul  5 20:11:07 1999
@@ -24,11 +24,8 @@
 
 /* Our copyright info must remain in the binary. */
 static const char *version =
-"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -44,6 +41,13 @@
 #include <linux/etherdevice.h>
 #include "8390.h"
 
+#if defined(__powerpc__)
+#define inl_le(addr)  le32_to_cpu(inl(addr))
+#define inw_le(addr)  le16_to_cpu(inw(addr))
+#define insl insl_ns
+#define outsl outsl_ns
+#endif
+
 /* Set statically or when loading the driver module. */
 static int debug = 1;
 
@@ -58,19 +62,34 @@
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE	0x40 */
 
+#define ne2k_flags reg0			/* Rename an existing field to store flags! */
+
+/* Only the low 8 bits are usable for non-init-time flags! */
+enum {
+	HOLTEK_FDX=1, 		/* Full duplex -> set 0x80 at offset 0x20. */
+	ONLY_16BIT_IO=2, ONLY_32BIT_IO=4,	/* Chip can do only 16/32-bit xfers. */
+	STOP_PG_0x60=0x100,
+};
+
+/* This will eventually be converted to the standard PCI probe table. */
+
 static struct {
 	unsigned short vendor, dev_id;
 	char *name;
+	int flags;
 }
 pci_clone_list[] __initdata = {
-	{0x10ec, 0x8029, "RealTek RTL-8029"},
-	{0x1050, 0x0940, "Winbond 89C940"},
-	{0x11f6, 0x1401, "Compex RL2000"},
-	{0x8e2e, 0x3000, "KTI ET32P2"},
-	{0x4a14, 0x5000, "NetVin NV5000SC"},
-	{0x1106, 0x0926, "Via 82C926"},
-	{0x10bd, 0x0e34, "SureCom NE34"},
-	{0x1050, 0x5a5a, "Winbond"},
+	{0x10ec, 0x8029, "RealTek RTL-8029", 0},
+	{0x1050, 0x0940, "Winbond 89C940", 0},
+	{0x11f6, 0x1401, "Compex RL2000", 0},
+	{0x8e2e, 0x3000, "KTI ET32P2", 0},
+	{0x4a14, 0x5000, "NetVin NV5000SC", 0},
+	{0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
+	{0x10bd, 0x0e34, "SureCom NE34", 0},
+	{0x1050, 0x5a5a, "Winbond", 0},
+	{0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
+	{0x12c3, 0x5598, "Holtek HT80229",
+	 ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
 	{0,}
 };
 
@@ -86,7 +105,8 @@
 #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
 
 int ne2k_pci_probe(struct device *dev);
-static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq);
+static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq,
+									  int chip_idx);
 
 static int ne2k_pci_open(struct device *dev);
 static int ne2k_pci_close(struct device *dev);
@@ -115,17 +135,13 @@
 int
 init_module(void)
 {
-	int retval;
-
 	/* We must emit version information. */
 	if (debug)
 		printk(KERN_INFO "%s", version);
 
-	retval = ne2k_pci_probe(0);
-
-	if (retval) {
-		printk(KERN_NOTICE "ne2k-pci.c: no (useable) cards found, driver NOT installed.\n");
-		return retval;
+	if (ne2k_pci_probe(0)) {
+		printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
+		return -ENODEV;
 	}
 	lock_8390_module();
 	return 0;
@@ -170,7 +186,7 @@
 {"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
 #endif
 
-__initfunc (int ne2k_pci_probe(struct device *dev))
+int __init ne2k_pci_probe(struct device *dev)
 {
 	struct pci_dev *pdev = NULL;
 	int cards_found = 0;
@@ -225,7 +241,7 @@
 
 		printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n",
 			   pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
-		dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line);
+		dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line, i);
 		if (dev == 0) {
 			/* Should not happen. */
 			printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n",
@@ -247,11 +263,10 @@
 	return cards_found ? 0 : -ENODEV;
 }
 
-__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq))
+static struct device __init *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq, int chip_idx)
 {
 	int i;
 	unsigned char SA_prom[32];
-	const char *name = NULL;
 	int start_page, stop_page;
 	int reg0 = inb(ioaddr);
 
@@ -273,6 +288,8 @@
 		}
 	}
 
+	dev = init_etherdev(dev, 0);
+
 	/* Reset card. Who knows what dain-bramaged state it was left in. */
 	{
 		unsigned long reset_start_time = jiffies;
@@ -321,59 +338,47 @@
 
 	}
 
-#ifdef notdef
-	/* Some broken PCI cards don't respect the byte-wide
-	   request in program_seq above, and hence don't have doubled up values.
-	*/
-	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
-		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
-		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
-		if (SA_prom[i] != SA_prom[i+1])
-			sa_prom_doubled = 0;
-	}
-
-	if (sa_prom_doubled)
-		for (i = 0; i < 16; i++)
-			SA_prom[i] = SA_prom[i+i];
-#else
-	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
-		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+	/* Note: all PCI cards have at least 16 bit access, so we don't have
+	   to check for 8 bit cards.  Most cards permit 32 bit access. */
 
-#endif
+	if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) {
+		for (i = 0; i < 4 ; i++)
+			((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
+	} else
+		for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
+			SA_prom[i] = inb(ioaddr + NE_DATAPORT);
 
 	/* We always set the 8390 registers for word mode. */
 	outb(0x49, ioaddr + EN0_DCFG);
 	start_page = NESM_START_PG;
-	stop_page = NESM_STOP_PG;
 
-	/* Set up the rest of the parameters. */
-	name = "PCI NE2000";
-
-	dev = init_etherdev(dev, 0);
+	stop_page =
+		pci_clone_list[chip_idx].flags&STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
 
+	/* Set up the rest of the parameters. */
 	dev->irq = irq;
 	dev->base_addr = ioaddr;
 
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) {
 		printk ("%s: unable to get memory for dev->priv.\n", dev->name);
-		kfree(dev);
 		return 0;
 	}
 
 	request_region(ioaddr, NE_IO_EXTENT, dev->name);
 
 	printk("%s: %s found at %#x, IRQ %d, ",
-		   dev->name, name, ioaddr, dev->irq);
+		   dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
 	for(i = 0; i < 6; i++) {
 		printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
 		dev->dev_addr[i] = SA_prom[i];
 	}
 
-	ei_status.name = name;
+	ei_status.name = pci_clone_list[chip_idx].name;
 	ei_status.tx_start_page = start_page;
 	ei_status.stop_page = stop_page;
 	ei_status.word16 = 1;
+	ei_status.ne2k_flags = pci_clone_list[chip_idx].flags;
 
 	ei_status.rx_start_page = start_page + TX_PAGES;
 #ifdef PACKETBUF_MEMSIZE
@@ -447,9 +452,9 @@
 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
 	if (ei_status.dmaing) {
 		printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr "
-			   "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
 			   dev->name, ei_status.dmaing, ei_status.irqlock,
-			   dev->interrupt);
+			   (int)dev->interrupt);
 		return;
 	}
 
@@ -461,11 +466,12 @@
 	outb(ring_page, nic_base + EN0_RSARHI);
 	outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
-#if defined(USE_LONGIO)
-	*(u32*)hdr = inl(NE_BASE + NE_DATAPORT);
-#else
-	insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-#endif
+	if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+	} else {
+		*(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT));
+		le16_to_cpus(&hdr->count);
+	}
 
 	outb(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
 	ei_status.dmaing &= ~0x01;
@@ -485,12 +491,14 @@
 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
 	if (ei_status.dmaing) {
 		printk("%s: DMAing conflict in ne2k_pci_block_input "
-			   "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
 			   dev->name, ei_status.dmaing, ei_status.irqlock,
-			   dev->interrupt);
+			   (int)dev->interrupt);
 		return;
 	}
 	ei_status.dmaing |= 0x01;
+	if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+		count = (count + 3) & 0xFFFC;
 	outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
 	outb(count & 0xff, nic_base + EN0_RCNTLO);
 	outb(count >> 8, nic_base + EN0_RCNTHI);
@@ -498,21 +506,21 @@
 	outb(ring_offset >> 8, nic_base + EN0_RSARHI);
 	outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
-#if defined(USE_LONGIO)
-	insl(NE_BASE + NE_DATAPORT, buf, count>>2);
-	if (count & 3) {
-		buf += count & ~3;
-		if (count & 2)
-			*((u16*)buf)++ = inw(NE_BASE + NE_DATAPORT);
-		if (count & 1)
-			*buf = inb(NE_BASE + NE_DATAPORT);
-	}
-#else
-	insw(NE_BASE + NE_DATAPORT,buf,count>>1);
-	if (count & 0x01) {
-		buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+	if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+		insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+		if (count & 0x01) {
+			buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+		}
+	} else {
+		insl(NE_BASE + NE_DATAPORT, buf, count>>2);
+		if (count & 3) {
+			buf += count & ~3;
+			if (count & 2)
+				*((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT));
+			if (count & 1)
+				*buf = inb(NE_BASE + NE_DATAPORT);
+		}
 	}
-#endif
 
 	outb(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
 	ei_status.dmaing &= ~0x01;
@@ -527,15 +535,18 @@
 
 	/* On little-endian it's always safe to round the count up for
 	   word writes. */
-	if (count & 0x01)
-		count++;
+	if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+		count = (count + 3) & 0xFFFC;
+	else
+		if (count & 0x01)
+			count++;
 
 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
 	if (ei_status.dmaing) {
 		printk("%s: DMAing conflict in ne2k_pci_block_output."
-			   "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
+			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
 			   dev->name, ei_status.dmaing, ei_status.irqlock,
-			   dev->interrupt);
+			   (int)dev->interrupt);
 		return;
 	}
 	ei_status.dmaing |= 0x01;
@@ -561,16 +572,16 @@
 	outb(0x00, nic_base + EN0_RSARLO);
 	outb(start_page, nic_base + EN0_RSARHI);
 	outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
-#if defined(USE_LONGIO)
-	outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
-	if (count & 3) {
-		buf += count & ~3;
-		if (count & 2)
-			outw(*((u16*)buf)++, NE_BASE + NE_DATAPORT);
+	if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+		outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+	} else {
+		outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
+		if (count & 3) {
+			buf += count & ~3;
+			if (count & 2)
+				outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT);
+		}
 	}
-#else
-	outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
-#endif
 
 	dma_start = jiffies;
 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne3210.c linux/drivers/net/ne3210.c
--- v2.3.9/linux/drivers/net/ne3210.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/ne3210.c	Tue Jul  6 19:08:33 1999
@@ -95,7 +95,7 @@
  *	PROM for a match against the value assigned to Novell.
  */
 
-__initfunc(int ne3210_probe(struct device *dev))
+int __init ne3210_probe(struct device *dev)
 {
 	unsigned short ioaddr = dev->base_addr;
 
@@ -122,7 +122,7 @@
 	return ENODEV;
 }
 
-__initfunc(int ne3210_probe1(struct device *dev, int ioaddr))
+int __init ne3210_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	unsigned long eisa_id;
diff -u --recursive --new-file v2.3.9/linux/drivers/net/olympic.c linux/drivers/net/olympic.c
--- v2.3.9/linux/drivers/net/olympic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/olympic.c	Tue Jul  6 10:11:40 1999
@@ -0,0 +1,1663 @@
+/*
+ *   olympic.c (c) 1999 Peter De Schrijver All Rights Reserved
+ *		   1999 Mike Phillips (phillim@amtrak.com)
+ *
+ *  Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic
+ *  chipset. 
+ *
+ *  Base Driver Skeleton:
+ *      Written 1993-94 by Donald Becker.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *  Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their 
+ *  assistance and perserverance with the testing of this driver.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ * 
+ *  4/27/99 - Alpha Release 0.1.0
+ *            First release to the public
+ *
+ *  6/8/99  - Official Release 0.2.0   
+ *            Merged into the kernel code 
+ *  
+ *  To Do:
+ *
+ *  Sanitize for smp
+ *
+ *  If Problems do Occur
+ *  Most problems can be rectified by either closing and opening the interface
+ *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult
+ *  if compiled into the kernel).
+ */
+
+/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */
+
+#define OLYMPIC_DEBUG 0
+
+/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel.
+ * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the
+ * kernel.
+ * Intended to be used to create a ring-error reporting network module 
+ * i.e. it will give you the source address of beaconers on the ring 
+ */
+
+#define OLYMPIC_NETWORK_MONITOR 0
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <net/checksum.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include "olympic.h"
+
+/* I've got to put some intelligence into the version number so that Peter and I know
+ * which version of the code somebody has got. 
+ * Version Number = a.b.c.d  where a.b.c is the level of code and d is the latest author.
+ * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike
+ * 
+ * Official releases will only have an a.b.c version number format.
+ */
+
+static char *version = 
+"Olympic.c v0.2.0 6/8/99 - Peter De Schrijver & Mike Phillips" ; 
+
+static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
+				   "Address Verification", "Neighbor Notification (Ring Poll)",
+				   "Request Parameters","FDX Registration Request",
+				   "FDX Duplicate Address Check", "Station registration Query Wait",
+				   "Unknown stage"};
+
+static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault",
+				   "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing",
+				   "Duplicate Node Address","Request Parameters","Remove Received",
+				   "Reserved", "Reserved", "No Monitor Detected for RPL", 
+				   "Monitor Contention failer for RPL", "FDX Protocol Error"};
+
+/* Module paramters */
+
+/* Ring Speed 0,4,16,100 
+ * 0 = Autosense         
+ * 4,16 = Selected speed only, no autosense
+ * This allows the card to be the first on the ring
+ * and become the active monitor.
+ * 100 = Nothing at present, 100mbps is autodetected
+ * if FDX is turned on. May be implemented in the future to 
+ * fail if 100mpbs is not detected.
+ *
+ * WARNING: Some hubs will allow you to insert
+ * at the wrong speed
+ */
+
+static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ;
+
+MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i");
+
+/* Packet buffer size */
+
+static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ;
+ 
+MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
+
+/* Message Level */
+
+static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; 
+
+MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; 
+
+static int olympic_scan(struct device *dev);
+static int olympic_init(struct device *dev);
+static int olympic_open(struct device *dev);
+static int olympic_xmit(struct sk_buff *skb, struct device *dev);
+static int olympic_close(struct device *dev);
+static void olympic_set_rx_mode(struct device *dev);
+static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats * olympic_get_stats(struct device *dev);
+static int olympic_set_mac_address(struct device *dev, void *addr) ; 
+static void olympic_arb_cmd(struct device *dev);
+static int olympic_change_mtu(struct device *dev, int mtu);
+static void olympic_srb_bh(struct device *dev) ; 
+static void olympic_asb_bh(struct device *dev) ; 
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+static int sprintf_info(char *buffer, struct device *dev) ; 
+#endif
+#endif
+
+__initfunc(int olympic_probe(struct device *dev)) 
+{
+	int cards_found;
+
+	cards_found=olympic_scan(dev);
+	return cards_found ? 0 : -ENODEV;
+}
+
+__initfunc(static int olympic_scan(struct device *dev)) 
+{
+	struct pci_dev *pci_device = NULL ;
+	struct olympic_private *olympic_priv;
+	int card_no = 0 ;
+	if (pci_present()) {
+
+		while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
+
+			pci_set_master(pci_device);
+
+			/* Check to see if io has been allocated, if so, we've already done this card,
+			   so continue on the card discovery loop  */
+
+			if (check_region(pci_device->base_address[0] & (~3), OLYMPIC_IO_SPACE)) {
+				card_no++ ; 
+				continue ; 
+			}
+
+			olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL);
+			memset(olympic_priv, 0, sizeof(struct olympic_private));
+			init_waitqueue_head(&olympic_priv->srb_wait);
+			init_waitqueue_head(&olympic_priv->trb_wait);
+#ifndef MODULE
+			dev=init_trdev(dev, 0);
+#endif
+			dev->priv=(void *)olympic_priv;
+#if OLYMPIC_DEBUG  
+			printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv);
+#endif 
+			dev->irq=pci_device->irq;
+			dev->base_addr=pci_device->base_address[0] & (~3);
+			dev->init=&olympic_init;
+			olympic_priv->olympic_mmio=ioremap(pci_device->base_address[1],256);
+			olympic_priv->olympic_lap=ioremap(pci_device->base_address[2],2048);
+			
+			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
+				olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; 
+			else
+				olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; 
+
+			olympic_priv->olympic_ring_speed = ringspeed[card_no] ; 
+			olympic_priv->olympic_message_level = message_level[card_no] ; 
+			olympic_priv->olympic_multicast_set  = 0 ; 
+	
+			if(olympic_init(dev)==-1) {
+				unregister_netdevice(dev);
+				kfree(dev->priv);
+				return 0;
+			}				
+
+			dev->open=&olympic_open;
+			dev->hard_start_xmit=&olympic_xmit;
+			dev->change_mtu=&olympic_change_mtu;
+
+			dev->stop=&olympic_close;
+			dev->do_ioctl=NULL;
+			dev->set_multicast_list=&olympic_set_rx_mode;
+			dev->get_stats=&olympic_get_stats ;
+			dev->set_mac_address=&olympic_set_mac_address ;  
+			return 1; 
+		}
+	}
+	return  0 ;
+}
+
+
+__initfunc(static int olympic_init(struct device *dev)) 
+{
+    	struct olympic_private *olympic_priv;
+	__u8 *olympic_mmio, *init_srb,*adapter_addr;
+	unsigned long t; 
+	unsigned int uaa_addr;
+
+    	olympic_priv=(struct olympic_private *)dev->priv;
+	olympic_mmio=olympic_priv->olympic_mmio;
+
+	printk("%s \n", version);
+	printk("%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
+
+	request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic");
+	writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
+	t=jiffies;
+	while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
+		schedule();		
+		if(jiffies-t > 40*HZ) {
+			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
+			release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; 
+			return -1;
+		}
+	}
+
+#if OLYMPIC_DEBUG
+	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
+	printk("GPR: %x\n",readw(olympic_mmio+GPR));
+	printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK));
+#endif
+	/* Aaaahhh, You have got to be real careful setting GPR, the card
+	   holds the previous values from flash memory, including autosense 
+           and ring speed */
+
+	writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
+	
+	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
+		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name);
+	} else if (olympic_priv->olympic_ring_speed == 16) {
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name);
+		writel(GPR_16MBPS, olympic_mmio+GPR);
+	} else if (olympic_priv->olympic_ring_speed == 4) {
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; 
+		writel(0, olympic_mmio+GPR);
+	} 
+	
+	writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
+
+#if OLYMPIC_DEBUG
+	printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
+#endif
+	/* start solo init */
+	writel((1<<15),olympic_mmio+SISR_MASK_SUM);
+
+	t=jiffies;
+	while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) {
+		schedule();		
+		if(jiffies-t > 40*HZ) {
+			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
+			release_region(dev->base_addr, OLYMPIC_IO_SPACE); 
+			return -1;
+		}
+	}
+	
+	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+
+#if OLYMPIC_DEBUG
+	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+#endif
+
+	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+
+#if OLYMPIC_DEBUG		
+{
+	int i;
+	printk("init_srb(%p): ",init_srb);
+	for(i=0;i<20;i++)
+		printk("%x ",readb(init_srb+i));
+	printk("\n");
+}
+#endif	
+	if(readw(init_srb+6)) {
+		printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6));
+		release_region(dev->base_addr, OLYMPIC_IO_SPACE);
+		return -1;
+	}
+
+	uaa_addr=ntohs(readw(init_srb+8));
+
+#if OLYMPIC_DEBUG
+	printk("UAA resides at %x\n",uaa_addr);
+#endif
+
+	writel(uaa_addr,olympic_mmio+LAPA);
+	adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
+
+#if OLYMPIC_DEBUG
+	printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+			readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
+			readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
+#endif
+
+	memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
+
+	olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; 
+	olympic_priv->olympic_parms_addr      = ntohs(readw(init_srb + 14)) ; 
+
+	return 0;
+
+}
+
+static int olympic_open(struct device *dev) 
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
+	unsigned long flags;
+	char open_error[255] ; 
+	int i, open_finished = 1 ;
+
+#if OLYMPIC_NETWORK_MONITOR
+	__u8 *oat ; 
+	__u8 *opt ; 
+#endif
+
+	if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
+		return -EAGAIN;
+	}
+
+#if OLYMPIC_DEBUG
+	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
+	printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR));
+#endif
+
+	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
+
+	writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */
+
+	writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */
+
+	/* adapter is closed, so SRB is pointed to by LAPWWO */
+
+	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	
+#if OLYMPIC_DEBUG
+	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+	printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
+	printk("Before the open command \n");
+#endif	
+	do {
+		int i;
+
+		save_flags(flags);
+		cli();
+		for(i=0;i<SRB_COMMAND_SIZE;i+=4)
+			writel(0,init_srb+i);
+		if(SRB_COMMAND_SIZE & 2)
+			writew(0,init_srb+(SRB_COMMAND_SIZE & ~3));
+		if(SRB_COMMAND_SIZE & 1)
+			writeb(0,init_srb+(SRB_COMMAND_SIZE & ~1));
+
+		writeb(SRB_OPEN_ADAPTER,init_srb) ; 	/* open */
+		writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2);
+
+		/* If Network Monitor, instruct card to copy MAC frames through the ARB */
+
+#if OLYMPIC_NETWORK_MONITOR
+		writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON),init_srb+8);
+#else
+		writew(OPEN_ADAPTER_ENABLE_FDX,init_srb+8);
+#endif		
+
+		if (olympic_priv->olympic_laa[0]) {
+			writeb(olympic_priv->olympic_laa[0],init_srb+12);
+			writeb(olympic_priv->olympic_laa[1],init_srb+13);
+			writeb(olympic_priv->olympic_laa[2],init_srb+14);
+			writeb(olympic_priv->olympic_laa[3],init_srb+15);
+			writeb(olympic_priv->olympic_laa[4],init_srb+16);
+			writeb(olympic_priv->olympic_laa[5],init_srb+17);
+			memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ;  
+		} 	
+		writeb(1,init_srb+30);
+	
+		olympic_priv->srb_queued=1;
+
+		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+ 		while(olympic_priv->srb_queued) {        
+        		interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ);
+        		if(signal_pending(current))	{            
+				printk(KERN_WARNING "%s: SRB timed out.\n",
+                			dev->name);
+            			printk(KERN_WARNING "SISR=%x MISR=%x\n",
+                			readl(olympic_mmio+SISR),
+                			readl(olympic_mmio+LISR));
+            			olympic_priv->srb_queued=0;
+            			break;
+        		}
+    		}
+		restore_flags(flags);
+#if OLYMPIC_DEBUG
+		printk("init_srb(%p): ",init_srb);
+		for(i=0;i<20;i++)
+			printk("%x ",readb(init_srb+i));
+		printk("\n");
+#endif
+		
+		/* If we get the same return response as we set, the interrupt wasn't raised and the open
+                 * timed out.
+		 */
+
+		if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) {
+			printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; 
+			return -EIO ; 
+		}	
+
+		if(readb(init_srb+2)!=0) {
+			if (readb(init_srb+2) == 0x07) {  
+				if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */
+					printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); 
+					open_finished = 0 ;  
+				} else {
+
+					strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; 
+					strcat(open_error," - ") ; 
+					strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ;
+
+					if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { 
+						printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name);
+						printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name);
+						free_irq(dev->irq, dev);
+						return -EIO ;
+					}
+
+					printk(KERN_WARNING "%s: %s\n",dev->name,open_error);
+					free_irq(dev->irq,dev) ; 
+					return -EIO ; 
+ 
+				}	/* if autosense && open_finished */
+			} else {  
+				printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]);
+				free_irq(dev->irq, dev);
+				return -EIO;
+			} 
+		} else 
+			open_finished = 1 ; 
+	} while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */	
+
+	if (readb(init_srb+18) & (1<<3)) 
+		if (olympic_priv->olympic_message_level) 
+			printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name);
+
+	if (readb(init_srb+18) & (1<<1))
+		olympic_priv->olympic_ring_speed = 100 ; 
+	else if (readb(init_srb+18) & 1)
+		olympic_priv->olympic_ring_speed = 16 ; 
+	else
+		olympic_priv->olympic_ring_speed = 4 ; 
+
+	if (olympic_priv->olympic_message_level) 
+		printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed);
+
+	olympic_priv->asb=ntohs(readw(init_srb+8));
+	olympic_priv->srb=ntohs(readw(init_srb+10));
+	olympic_priv->arb=ntohs(readw(init_srb+12));
+	olympic_priv->trb=ntohs(readw(init_srb+16));
+
+	olympic_priv->olympic_receive_options = 0x01 ; 
+	olympic_priv->olympic_copy_all_options = 0 ; 
+	
+	/* setup rx ring */
+	
+	writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ 
+
+	writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */
+
+	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+
+		struct sk_buff *skb;
+		
+		skb=dev_alloc_skb(olympic_priv->pkt_buf_sz);
+		if(skb == NULL)
+			break;
+
+		skb->dev = dev;
+
+		olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data);
+		olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; 
+		olympic_priv->rx_ring_skb[i]=skb;
+	}
+
+	if (i==0) {
+		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name);
+		free_irq(dev->irq, dev);
+		return -EIO;
+	}
+
+	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ);
+	writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA);
+	writew(i,olympic_mmio+RXDESCQCNT);
+		
+	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ);
+	writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA);
+	
+ 	olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1;	/* last processed rx status */
+	olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1;  
+
+	writew(i,olympic_mmio+RXSTATQCNT);
+
+#if OLYMPIC_DEBUG 
+	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
+	printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+	printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) );
+	printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) );
+	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
+
+	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+#endif
+
+	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
+
+#if OLYMPIC_DEBUG 
+	printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ));
+	printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]);
+	printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);
+#endif 
+
+	writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM);
+
+	/* setup tx ring */
+
+	writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */
+	for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) 
+		olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef;
+
+	olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE;
+	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1);
+	writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1);
+	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1);
+	
+	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1);
+	writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1);
+	writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1);
+		
+	olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
+	olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
+
+	writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM);
+
+#if OLYMPIC_DEBUG 
+	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
+	printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK));
+#endif
+
+#if OLYMPIC_NETWORK_MONITOR
+	oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+	opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+
+	printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+	printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+		    readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+
+	printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
+			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
+
+
+#endif 	
+	
+	dev->start = 1;
+	dev->interrupt=0;
+	dev->tbusy=0;
+
+	MOD_INC_USE_COUNT ;
+	return 0;
+	
+}	
+
+/*
+ *	When we enter the rx routine we do not know how many frames have been 
+ *	queued on the rx channel.  Therefore we start at the next rx status
+ *	position and travel around the receive ring until we have completed
+ *	all the frames.
+ *
+ *	This means that we may process the frame before we receive the end
+ *	of frame interrupt. This is why we always test the status instead
+ *	of blindly processing the next frame.
+ *	
+ */
+static void olympic_rx(struct device *dev)
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	struct olympic_rx_status *rx_status;
+	struct olympic_rx_desc *rx_desc ; 
+	int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len;
+	struct sk_buff *skb, *skb2;
+	int i;
+
+	rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; 
+ 
+	while (rx_status->status_buffercnt) { 
+
+		olympic_priv->rx_status_last_received++ ;
+		olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+#if OLYMPIC_DEBUG
+		printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); 
+		printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen);	
+#endif
+		length=rx_status->fragmentcnt_framelen & 0xffff;
+		buffer_cnt = rx_status->status_buffercnt & 0xffff ; 
+		i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ 
+		frag_len = rx_status->fragmentcnt_framelen >> 16 ; 
+
+#if OLYMPIC_DEBUG 
+		printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt);
+#endif
+
+		if(rx_status->status_buffercnt & 0xC0000000) {
+			if (rx_status->status_buffercnt & 0x3B000000) {
+				if (olympic_priv->olympic_message_level) {
+					if (rx_status->status_buffercnt & (1<<29))  /* Rx Frame Truncated */
+						printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */
+						printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */
+						printk(KERN_WARNING "%s: No receive buffers \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */
+						printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name);
+					if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */
+						printk(KERN_WARNING "%s: Received Error Detect \n",dev->name);
+				} 
+				olympic_priv->rx_ring_last_received += i ; 
+				olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; 
+				olympic_priv->olympic_stats.rx_errors++;	 
+			} else {	
+			
+				if (buffer_cnt == 1) {
+					skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; 
+				} else {
+					skb = dev_alloc_skb(length) ; 
+				}
+
+				if (skb == NULL) {
+					printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ;
+					olympic_priv->olympic_stats.rx_dropped++ ; 
+					/* Update counters even though we don't transfer the frame */
+					olympic_priv->rx_ring_last_received += i ; 
+					olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ;  
+				} else  {
+					skb->dev = dev ; 
+
+					/* Optimise based upon number of buffers used. 
+			   	   	   If only one buffer is used we can simply swap the buffers around.
+			   	   	   If more than one then we must use the new buffer and copy the information
+			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
+                               	   	   altering the buffer size. */
+				
+ 					if (buffer_cnt==1) {
+						olympic_priv->rx_ring_last_received++ ; 
+						olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+						rx_ring_last_received = olympic_priv->rx_ring_last_received ;
+						skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; 
+						skb_put(skb2,length);
+						skb2->protocol = tr_type_trans(skb2,dev);
+						olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data);
+						olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; 
+						olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; 
+						netif_rx(skb2) ; 
+					} else {
+						do { /* Walk the buffers */ 
+							olympic_priv->rx_ring_last_received++ ; 
+							olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1);
+							rx_ring_last_received = olympic_priv->rx_ring_last_received ; 
+							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
+							cpy_length = (i == 1 ? frag_len : rx_desc->res_length); 
+							memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; 
+						} while (--i) ; 
+		
+						skb->protocol = tr_type_trans(skb,dev);
+						netif_rx(skb) ; 
+					} 
+					olympic_priv->olympic_stats.rx_packets++ ; 
+					olympic_priv->olympic_stats.rx_bytes += length ; 
+				} /* if skb == null */
+			} /* If status & 0x3b */
+
+		} else { /*if buffercnt & 0xC */
+			olympic_priv->rx_ring_last_received += i ; 
+			olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; 
+		} 
+
+		rx_status->fragmentcnt_framelen = 0 ; 
+		rx_status->status_buffercnt = 0 ; 
+		rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]);
+
+		writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) |  buffer_cnt , olympic_mmio+RXENQ); 
+	} /* while */
+
+}
+
+static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+{
+	struct device *dev= (struct device *)dev_id;
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	__u32 sisr;
+	__u8 *adapter_check_area ; 
+	
+	sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ 
+	
+	if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ 
+		return ;
+
+	if (dev->interrupt) 
+		printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; 
+
+	dev->interrupt = 1 ; 
+
+	if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |  
+			SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) {  
+	
+		if(sisr & SISR_SRB_REPLY) {
+			if(olympic_priv->srb_queued==1) {
+				wake_up_interruptible(&olympic_priv->srb_wait);
+			} else if (olympic_priv->srb_queued==2) { 
+				olympic_srb_bh(dev) ; 
+			}
+			olympic_priv->srb_queued=0;
+		} /* SISR_SRB_REPLY */
+
+		if (sisr & SISR_TX1_EOF) {
+			olympic_priv->tx_ring_last_status++;
+			olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1);
+			olympic_priv->free_tx_ring_entries++;
+			olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
+			olympic_priv->olympic_stats.tx_packets++ ; 
+			dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
+			olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
+			olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
+
+			if(dev->tbusy) {
+				dev->tbusy=0;
+				mark_bh(NET_BH);
+			}
+		} /* SISR_TX1_EOF */
+	
+		if (sisr & SISR_RX_STATUS) {
+			olympic_rx(dev);
+		} /* SISR_RX_STATUS */
+	
+		if (sisr & SISR_ADAPTER_CHECK) {
+			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
+			writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+			adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; 
+			printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
+			dev->interrupt = 0  ; 	
+			free_irq(dev->irq, dev) ; 
+	
+		} /* SISR_ADAPTER_CHECK */
+	
+		if (sisr & SISR_ASB_FREE) {
+			/* Wake up anything that is waiting for the asb response */  
+			if (olympic_priv->asb_queued) {
+				olympic_asb_bh(dev) ; 
+			}
+		} /* SISR_ASB_FREE */
+	
+		if (sisr & SISR_ARB_CMD) {
+			olympic_arb_cmd(dev) ; 
+		} /* SISR_ARB_CMD */
+	
+		if (sisr & SISR_TRB_REPLY) {
+			/* Wake up anything that is waiting for the trb response */
+			if (olympic_priv->trb_queued) {
+				wake_up_interruptible(&olympic_priv->trb_wait);
+			}
+			olympic_priv->trb_queued = 0 ; 
+		} /* SISR_TRB_REPLY */	
+	
+		if (sisr & SISR_RX_NOBUF) {
+			/* According to the documentation, we don't have to do anything, but trapping it keeps it out of
+                  	   	   /var/log/messages.  */
+		} /* SISR_RX_NOBUF */
+	} else { 
+		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr);
+		printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ;
+	} /* One if the interrupts we want */
+
+	dev->interrupt = 0 ;  
+
+	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
+
+}	
+
+static int olympic_xmit(struct sk_buff *skb, struct device *dev) 
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+    __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		return 1;
+	}
+
+	if(olympic_priv->free_tx_ring_entries) {
+		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data);
+		olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000);
+		olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb;
+		olympic_priv->free_tx_ring_entries--;
+
+        	olympic_priv->tx_ring_free++;
+        	olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1);
+
+
+		writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
+
+		dev->tbusy=0;		
+
+		return 0;
+	} else 
+		return 1;
+
+}
+	
+
+static int olympic_close(struct device *dev) 
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+    	__u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
+	unsigned long flags;
+	int i;
+
+	writel(olympic_priv->srb,olympic_mmio+LAPA);
+	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+	
+    	writeb(SRB_CLOSE_ADAPTER,srb+0);
+	writeb(0,srb+1);
+	writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+
+	save_flags(flags);
+	cli();	
+
+	olympic_priv->srb_queued=1;
+
+	writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+	while(olympic_priv->srb_queued) {
+	        interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ);
+        	if(signal_pending(current))	{            
+			printk(KERN_WARNING "%s: SRB timed out.\n",
+                		dev->name);
+            		printk(KERN_WARNING "SISR=%x MISR=%x\n",
+                	readl(olympic_mmio+SISR),
+                	readl(olympic_mmio+LISR));
+            		olympic_priv->srb_queued=0;
+            		break;
+        	}
+    	}
+
+	restore_flags(flags) ; 
+	olympic_priv->rx_status_last_received++;
+	olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+	
+	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+		dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+		olympic_priv->rx_status_last_received++;
+		olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+	}
+
+	/* reset tx/rx fifo's and busmaster logic */
+
+	writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
+	udelay(1);
+	writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
+
+#if OLYMPIC_DEBUG
+	printk("srb(%p): ",srb);
+	for(i=0;i<4;i++)
+		printk("%x ",readb(srb+i));
+	printk("\n");
+#endif
+    	dev->start = 0;
+	free_irq(dev->irq,dev);
+
+	MOD_DEC_USE_COUNT ; 
+	return 0;
+	
+}
+
+static void olympic_set_rx_mode(struct device *dev) 
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+	__u8 options = 0, set_mc_list = 0 ; 
+	__u8 *srb, *ata ;
+	struct dev_mc_list *dmi ; 
+
+	writel(olympic_priv->srb,olympic_mmio+LAPA);
+	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+	options = olympic_priv->olympic_copy_all_options; 
+
+	if (dev->flags&IFF_PROMISC)  
+		options |= (3<<5) ; /* All LLC and MAC frames, all through the main rx channel */  
+	else
+		options &= ~(3<<5) ; 
+
+	if (dev->mc_count) {  
+		set_mc_list = 1 ; 
+	}
+
+	/* Only issue the srb if there is a change in options */
+
+	if ((options ^ olympic_priv->olympic_copy_all_options)) { 
+	
+		/* Now to issue the srb command to alter the copy.all.options */
+	
+		writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb);
+		writeb(0,srb+1);
+		writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+		writeb(0,srb+3);
+		writeb(olympic_priv->olympic_receive_options,srb+4);
+		writeb(options,srb+5);
+
+		olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+		olympic_priv->olympic_copy_all_options = options ;
+		
+		return ;  
+	} 
+
+	if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */ 
+
+		dmi = dev->mc_list ; 
+
+		if (set_mc_list) { /* Turn multicast on */
+
+			/* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
+                         * We do this with a set functional address mask.
+			 */
+						
+			ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
+			if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */ 
+				writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				writeb(0,srb+4);
+				writeb(0,srb+5);
+				writeb(readb(ata+10),srb+6);
+				writeb(readb(ata+11)|4,srb+7);
+				writeb(readb(ata+12),srb+8);
+				writeb(readb(ata+13),srb+9);
+			
+				olympic_priv->srb_queued = 2 ; 
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+				olympic_priv->olympic_multicast_set = 1 ;  
+			}    
+
+
+		} else { /* Turn multicast off */
+	
+			ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
+			if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */ 
+				writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				writeb(0,srb+4);
+				writeb(0,srb+5);
+				writeb(readb(ata+10),srb+6);
+				writeb(readb(ata+11) & ~4,srb+7);
+				writeb(readb(ata+12),srb+8);
+				writeb(readb(ata+13),srb+9);
+			
+				olympic_priv->srb_queued = 2 ; 
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);	
+
+				olympic_priv->olympic_multicast_set = 0 ; 
+			}
+		} 		
+
+	}
+
+
+}
+
+static void olympic_srb_bh(struct device *dev) 
+{ 
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+   	__u8 *olympic_mmio = olympic_priv->olympic_mmio ; 
+	__u8 *srb;
+
+	writel(olympic_priv->srb,olympic_mmio+LAPA);
+	srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
+
+	switch (readb(srb)) { 
+
+		/* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) 
+                 * At some point we should do something if we get an error, such as
+                 * resetting the IFF_PROMISC flag in dev
+		 */
+
+		case SRB_MODIFY_RECEIVE_OPTIONS:
+			switch (readb(srb+2)) { 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name);
+					break ; 
+				default:
+					if (olympic_priv->olympic_message_level) 
+						printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; 
+					break ; 	
+			} /* switch srb[2] */ 
+			break ;
+		
+		/* SRB_SET_GROUP_ADDRESS - Multicast group setting 
+                 */
+
+		case SRB_SET_GROUP_ADDRESS:
+			switch (readb(srb+2)) { 
+				case 0x00:
+					olympic_priv->olympic_multicast_set = 1 ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ;
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); 
+					break ;
+				case 0x3c:
+					printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; 
+					break ;
+				case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */
+					printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; 
+					break ;  
+				case 0x55:
+					printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; 
+					break ;
+				default:
+					break ; 
+			} /* switch srb[2] */ 
+			break ; 
+
+		/* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list
+ 		 */
+
+		case SRB_RESET_GROUP_ADDRESS:
+			switch (readb(srb+2)) { 
+				case 0x00:
+					olympic_priv->olympic_multicast_set = 0 ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+				case 0x39: /* Must deal with this if individual multicast addresses used */
+					printk(KERN_INFO "%s: Group address not found \n",dev->name); 
+					break ;
+				default:
+					break ; 
+			} /* switch srb[2] */
+			break ; 
+
+		
+		/* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode 
+		 */
+
+		case SRB_SET_FUNC_ADDRESS:
+			switch (readb(srb+2)) { 
+				case 0x00:
+					if (olympic_priv->olympic_message_level)
+						printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; 
+					break ;
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+				default:
+					break ; 
+			} /* switch srb[2] */
+			break ; 
+	
+		/* SRB_READ_LOG - Read and reset the adapter error counters
+ 		 */
+
+		case SRB_READ_LOG:
+			switch (readb(srb+2)) { 
+				case 0x00: 
+					if (olympic_priv->olympic_message_level) 
+						printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+			
+			} /* switch srb[2] */
+			break ; 
+		
+		/* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */
+
+		case SRB_READ_SR_COUNTERS:
+			switch (readb(srb+2)) { 
+				case 0x00: 
+					if (olympic_priv->olympic_message_level) 
+						printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; 
+					break ; 
+				case 0x01:
+					printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+					break ; 
+				case 0x04:
+					printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
+					break ; 
+				default:
+					break ; 
+			} /* switch srb[2] */
+			break ;
+ 
+		default:
+			printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name);
+			break ; 
+	} /* switch srb[0] */
+
+} 
+
+static struct net_device_stats * olympic_get_stats(struct device *dev)
+{
+	struct olympic_private *olympic_priv ;
+	olympic_priv=(struct olympic_private *) dev->priv;
+	return (struct net_device_stats *) &olympic_priv->olympic_stats; 
+}
+
+static int olympic_set_mac_address (struct device *dev, void *addr) 
+{
+	struct sockaddr *saddr = addr ; 
+	struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; 
+
+	if (dev->start) { 
+		printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
+		return -EIO ; 
+	}
+
+	memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; 
+	
+	if (olympic_priv->olympic_message_level) { 
+ 		printk(KERN_INFO "%s: MAC/LAA Set to  = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0],
+		olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2],
+		olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4],
+		olympic_priv->olympic_laa[5]);
+	} 
+
+	return 0 ; 
+}
+
+static void olympic_arb_cmd(struct device *dev)
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+    	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	__u8 *arb_block, *asb_block, *srb  ; 
+	__u8 header_len ; 
+	__u16 frame_len, buffer_len ;
+	struct sk_buff *mac_frame ;  
+	__u8 *buf_ptr ;
+	__u8 *frame_data ;  
+	__u16 buff_off ; 
+	__u16 lan_status = 0, lan_status_diff  ; /* Initialize to stop compiler warning */
+	__u8 fdx_prot_error ; 
+	__u16 next_ptr;
+
+#if OLYMPIC_NETWORK_MONITOR
+	struct trh_hdr *mac_hdr ; 
+#endif
+
+	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+	srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
+	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
+
+	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
+
+		header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */	
+		frame_len = ntohs(readw(arb_block + 10)) ; 
+
+		buff_off = ntohs(readw(arb_block + 6)) ;
+		
+		buf_ptr = olympic_priv->olympic_lap + buff_off ; 
+
+#if OLYMPIC_DEBUG
+{
+		int i;
+		frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
+
+		for (i=0 ;  i < 14 ; i++) { 
+			printk("Loc %d = %02x\n",i,readb(frame_data + i)); 
+		}
+
+		printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+}
+#endif 
+		mac_frame = dev_alloc_skb(frame_len) ; 
+
+		/* Walk the buffer chain, creating the frame */
+
+		do {
+			frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; 
+			buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+			memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ;
+			next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
+
+		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
+
+#if OLYMPIC_NETWORK_MONITOR
+		printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+		mac_hdr = (struct trh_hdr *)mac_frame->data ; 
+		printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
+		printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
+#endif
+		mac_frame->dev = dev ; 
+		mac_frame->protocol = tr_type_trans(mac_frame,dev);
+		netif_rx(mac_frame) ; 	
+
+		/* Now tell the card we have dealt with the received frame */
+
+		/* Set LISR Bit 1 */
+		writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
+
+		/* Is the ASB free ? */ 	
+		
+		if (!(readl(olympic_priv->olympic_mmio + SISR) & SISR_ASB_FREE)) {
+			olympic_priv->asb_queued = 1 ; 
+			writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); 
+			return ; 	
+			/* Drop out and wait for the bottom half to be run */
+		}
+		
+		writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
+		writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
+		writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
+		writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */		
+
+		writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
+		
+		olympic_priv->asb_queued = 2 ; 
+	
+		return ; 	
+		
+	} else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */
+		lan_status = readw(arb_block+6);
+		fdx_prot_error = readb(arb_block+8) ; 
+		
+		/* Issue ARB Free */
+		writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM);
+
+		lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; 
+
+		if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { 
+			if (lan_status_diff & LSC_LWF) 
+					printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name);
+			if (lan_status_diff & LSC_ARW) 
+					printk(KERN_WARNING "%s: Auto removal error\n",dev->name);
+			if (lan_status_diff & LSC_FPE)
+					printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name);
+			if (lan_status_diff & LSC_RR) 
+					printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name);
+		
+			/* Adapter has been closed by the hardware */
+		
+			/* reset tx/rx fifo's and busmaster logic */
+
+			writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
+			udelay(1);
+			writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
+			dev->tbusy = 1 ;
+			dev->interrupt = 1 ; 
+			dev->start = 0 ; 
+			olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; 
+			free_irq(dev->irq,dev);
+			
+			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
+	
+		} /* If serious error */
+		
+		if (olympic_priv->olympic_message_level) { 
+			if (lan_status_diff & LSC_SIG_LOSS) 
+					printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; 
+			if (lan_status_diff & LSC_HARD_ERR)
+					printk(KERN_INFO "%s: Beaconing \n",dev->name);
+			if (lan_status_diff & LSC_SOFT_ERR)
+					printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name);
+			if (lan_status_diff & LSC_TRAN_BCN) 
+					printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
+			if (lan_status_diff & LSC_SS) 
+					printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
+			if (lan_status_diff & LSC_RING_REC)
+					printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name);
+			if (lan_status_diff & LSC_FDX_MODE)
+					printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name);
+		} 	
+		
+		if (lan_status_diff & LSC_CO) { 
+					
+				if (olympic_priv->olympic_message_level) 
+					printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
+					
+				/* Issue READ.LOG command */
+
+				writeb(SRB_READ_LOG, srb);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				writeb(0,srb+4);
+				writeb(0,srb+5);
+					
+				olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+					
+		}
+
+		if (lan_status_diff & LSC_SR_CO) { 
+
+				if (olympic_priv->olympic_message_level)
+					printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name);
+
+				/* Issue a READ.SR.COUNTERS */
+				
+				writeb(SRB_READ_SR_COUNTERS,srb);
+				writeb(0,srb+1);
+				writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+				writeb(0,srb+3);
+				
+				olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */
+
+				writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+
+		}
+
+		olympic_priv->olympic_lan_status = lan_status ; 
+	
+	}  /* Lan.change.status */
+	else
+		printk(KERN_WARNING "%s: Unknown arb command \n", dev->name);
+}
+
+static void olympic_asb_bh(struct device *dev) 
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+	__u8 *arb_block, *asb_block ; 
+
+	arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
+	asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
+
+	if (olympic_priv->asb_queued == 1) {   /* Dropped through the first time */
+
+		writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */
+		writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */
+		writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */
+		writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */		
+
+		writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM);
+		olympic_priv->asb_queued = 2 ; 
+
+		return ; 
+	}
+
+	if (olympic_priv->asb_queued == 2) { 
+		switch (readb(asb_block+2)) {
+			case 0x01:
+				printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
+				break ;
+			case 0x26:
+				printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name);
+				break ;
+			case 0xFF:
+				/* Valid response, everything should be ok again */
+				break ;
+			default:
+				printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name);
+				break ;
+		}
+	}
+	olympic_priv->asb_queued = 0 ; 
+}
+ 
+static int olympic_change_mtu(struct device *dev, int mtu) 
+{
+	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+	__u16 max_mtu ; 
+
+	if (olympic_priv->olympic_ring_speed == 4)
+		max_mtu = 4500 ; 
+	else
+		max_mtu = 18000 ; 
+	
+	if (mtu > max_mtu)
+		return -EINVAL ; 
+	if (mtu < 100) 
+		return -EINVAL ; 
+
+	dev->mtu = mtu ; 
+	olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; 
+
+	return 0 ; 
+}
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	struct pci_dev *pci_device = NULL ;
+	int len=0;
+	off_t begin=0;
+	off_t pos=0;
+	int size;
+	
+	struct device *dev;
+
+
+	size = sprintf(buffer, 
+		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n");
+	
+	pos+=size;
+	len+=size;
+	
+
+	while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) {
+	
+		for (dev = dev_base; dev != NULL; dev = dev->next) 
+		{
+			if (dev->base_addr == (pci_device->base_address[0] & (~3)) ) { /* Yep, an Olympic device */	
+				size = sprintf_info(buffer+len, dev);
+				len+=size;
+				pos=begin+len;
+				
+				if(pos<offset)
+				{
+					len=0;
+					begin=pos;
+				}
+				if(pos>offset+length)
+					break;
+			} /* if */
+		} /* for */
+	} /* While */
+
+	*start=buffer+(offset-begin);	/* Start of wanted data */
+	len-=(offset-begin);		/* Start slop */
+	if(len>length)
+		len=length;		/* Ending slop */
+	return len;
+}
+
+static int sprintf_info(char *buffer, struct device *dev)
+{
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	__u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
+	__u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+	int size = 0 ; 
+		
+	size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
+ 	   dev->name); 
+
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
+	   dev->name,
+           dev->dev_addr[0],
+	   dev->dev_addr[1],
+	   dev->dev_addr[2],
+ 	   dev->dev_addr[3],
+	   dev->dev_addr[4],
+	   dev->dev_addr[5],
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
+	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
+	 
+	size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
+
+	size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n",
+	  dev->name) ; 
+	   
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x   : %04x     :  %04x    :\n",
+	  dev->name,
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
+
+	size += sprintf(buffer+size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
+	  dev->name) ; 
+	
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+	  dev->name,
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl))));
+
+	size += sprintf(buffer+size, "%6s: Beacon Details :  Tx  :  Rx  : NAUN Node Address : NAUN Node Phys : \n",
+	  dev->name) ; 
+
+	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x    : \n",
+	  dev->name,
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
+	  ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
+	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3));
+
+ 
+	return size;
+}
+#endif
+#endif 
+
+#ifdef MODULE
+
+static struct device* dev_olympic[OLYMPIC_MAX_ADAPTERS];
+
+int init_module(void)
+{
+        int i;
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent ; 
+
+	ent = create_proc_entry("net/olympic_tr",0,0); 
+	ent->read_proc = &olympic_proc_info ; 
+#endif
+#endif
+        for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) {
+		dev_olympic[i] = NULL;
+                dev_olympic[i] = init_trdev(dev_olympic[i], 0);
+                if (dev_olympic[i] == NULL)
+                        return -ENOMEM;
+
+		dev_olympic[i]->init      = &olympic_probe;
+
+	        if (register_trdev(dev_olympic[i]) != 0) {
+			kfree_s(dev_olympic[i], sizeof(struct device));
+			dev_olympic[i] = NULL;
+		        if (i == 0) {
+			        printk("Olympic: No IBM PCI Token Ring cards found in system.\n");
+		                return -EIO;
+			} else {
+			       	printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; 
+				return 0;
+			}
+	        }
+	}
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+        int i;
+
+        for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++)
+	        if (dev_olympic[i]) {
+			 unregister_trdev(dev_olympic[i]);
+			 release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE);
+			 kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private));
+			 kfree_s(dev_olympic[i], sizeof(struct device));
+			 dev_olympic[i] = NULL;
+                }
+
+#if OLYMPIC_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("net/olympic_tr", NULL) ; 
+#endif 
+#endif
+}
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.3.9/linux/drivers/net/olympic.h linux/drivers/net/olympic.h
--- v2.3.9/linux/drivers/net/olympic.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/olympic.h	Mon Jul  5 19:54:55 1999
@@ -0,0 +1,303 @@
+/*
+ *  olympic.h (c) 1999 Peter De Schrijver All Rights Reserved
+ *                1999 Mike Phillips (phillim@amtrak.com)
+ *
+ *  Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset.
+ *
+ *  Base Driver Skeleton:
+ *      Written 1993-94 by Donald Becker.
+ *
+ *      Copyright 1993 United States Government as represented by the
+ *      Director, National Security Agency.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ */
+
+#define CID 0x4e
+
+#define BCTL 0x70
+#define BCTL_SOFTRESET (1<<15)
+#define BCTL_MIMREB (1<<6)
+
+#define GPR 0x4a
+#define GPR_OPTI_BF (1<<6)
+#define GPR_NEPTUNE_BF (1<<4) 
+#define GPR_AUTOSENSE (1<<2)
+#define GPR_16MBPS (1<<3) 
+
+#define PAG 0x85
+#define LBC 0x8e
+
+#define LISR 0x10
+#define LISR_SUM 0x14
+#define LISR_RWM 0x18
+
+#define LISR_LIE (1<<15)
+#define LISR_SLIM (1<<13)
+#define LISR_SLI (1<<12)
+#define LISR_PCMSRMASK (1<<11)
+#define LISR_PCMSRINT (1<<10)
+#define LISR_WOLMASK (1<<9)
+#define LISR_WOL (1<<8)
+#define LISR_SRB_CMD (1<<5)
+#define LISR_ASB_REPLY (1<<4)
+#define LISR_ASB_FREE_REQ (1<<2)
+#define LISR_ARB_FREE (1<<1)
+#define LISR_TRB_FRAME (1<<0)
+
+#define SISR 0x20
+#define SISR_SUM 0x24
+#define SISR_RWM 0x28
+#define SISR_RR 0x2C
+#define SISR_RESMASK 0x30
+#define SISR_MASK 0x54
+#define SISR_MASK_SUM 0x58
+#define SISR_MASK_RWM 0x5C
+
+#define SISR_TX2_IDLE (1<<31)
+#define SISR_TX2_HALT (1<<29)
+#define SISR_TX2_EOF (1<<28)
+#define SISR_TX1_IDLE (1<<27)
+#define SISR_TX1_HALT (1<<25)
+#define SISR_TX1_EOF (1<<24)
+#define SISR_TIMEOUT (1<<23)
+#define SISR_RX_NOBUF (1<<22)
+#define SISR_RX_STATUS (1<<21)
+#define SISR_RX_HALT (1<<18)
+#define SISR_RX_EOF_EARLY (1<<16)
+#define SISR_MI (1<<15)
+#define SISR_PI (1<<13)
+#define SISR_ERR (1<<9)
+#define SISR_ADAPTER_CHECK (1<<6)
+#define SISR_SRB_REPLY (1<<5)
+#define SISR_ASB_FREE (1<<4)
+#define SISR_ARB_CMD (1<<3)
+#define SISR_TRB_REPLY (1<<2)
+
+#define EISR 0x34
+#define EISR_RWM 0x38
+#define EISR_MASK 0x3c
+
+#define LAPA 0x60
+#define LAPWWO 0x64
+#define LAPWWC 0x68
+#define LAPCTL 0x6C
+#define LAIPD 0x78
+#define LAIPDDINC 0x7C
+
+#define TIMER 0x50
+
+#define CLKCTL 0x74
+
+#define PM_CON 0x4
+
+#define BMCTL_SUM 0x40
+#define BMCTL_RWM 0x44
+#define BMCTL_TX2_DIS (1<<30) 
+#define BMCTL_TX1_DIS (1<<26) 
+#define BMCTL_RX_DIS (1<<22) 
+
+#define BMASR 0xcc
+
+#define RXDESCQ 0x90
+#define RXDESCQCNT 0x94
+#define RXCDA 0x98
+#define RXENQ 0x9C
+#define RXSTATQ 0xA0
+#define RXSTATQCNT 0xA4
+#define RXCSA 0xA8
+#define RXCLEN 0xAC
+#define RXHLEN 0xAE
+
+#define TXDESCQ_1 0xb0
+#define TXDESCQ_2 0xd0
+#define TXDESCQCNT_1 0xb4
+#define TXDESCQCNT_2 0xd4
+#define TXCDA_1 0xb8
+#define TXCDA_2 0xd8
+#define TXENQ_1 0xbc
+#define TXENQ_2 0xdc
+#define TXSTATQ_1 0xc0
+#define TXSTATQ_2 0xe0
+#define TXSTATQCNT_1 0xc4
+#define TXSTATQCNT_2 0xe4
+#define TXCSA_1 0xc8
+#define TXCSA_2 0xe8
+
+#define OLYMPIC_IO_SPACE 256
+
+#define SRB_COMMAND_SIZE 50
+
+#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */
+
+/* Defines for LAN STATUS CHANGE reports */
+#define LSC_SIG_LOSS 0x8000
+#define LSC_HARD_ERR 0x4000
+#define LSC_SOFT_ERR 0x2000
+#define LSC_TRAN_BCN 0x1000
+#define LSC_LWF      0x0800
+#define LSC_ARW      0x0400
+#define LSC_FPE      0x0200
+#define LSC_RR       0x0100
+#define LSC_CO       0x0080
+#define LSC_SS       0x0040
+#define LSC_RING_REC 0x0020
+#define LSC_SR_CO    0x0010
+#define LSC_FDX_MODE 0x0004
+
+/* Defines for OPEN ADAPTER command */
+
+#define OPEN_ADAPTER_EXT_WRAP (1<<15)
+#define OPEN_ADAPTER_DIS_HARDEE (1<<14)
+#define OPEN_ADAPTER_DIS_SOFTERR (1<<13)
+#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12)
+#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11)
+#define OPEN_ADAPTER_ENABLE_EC (1<<10)
+#define OPEN_ADAPTER_CONTENDER (1<<8)
+#define OPEN_ADAPTER_PASS_BEACON (1<<7)
+#define OPEN_ADAPTER_ENABLE_FDX (1<<6)
+#define OPEN_ADAPTER_ENABLE_RPL (1<<5)
+#define OPEN_ADAPTER_INHIBIT_ETR (1<<4)
+#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3)
+#define OPEN_ADAPTER_USE_OPTS2 (1<<0)
+
+#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15)
+
+/* Defines for SRB Commands */
+
+#define SRB_ACCESS_REGISTER 0x1f
+#define SRB_CLOSE_ADAPTER 0x04
+#define SRB_CONFIGURE_BRIDGE 0x0c
+#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a
+#define SRB_MODIFY_BRIDGE_PARMS 0x15
+#define SRB_MODIFY_OPEN_OPTIONS 0x01
+#define SRB_MODIFY_RECEIVE_OPTIONS 0x17
+#define SRB_NO_OPERATION 0x00
+#define SRB_OPEN_ADAPTER 0x03
+#define SRB_READ_LOG 0x08
+#define SRB_READ_SR_COUNTERS 0x16
+#define SRB_RESET_GROUP_ADDRESS 0x02
+#define SRB_SAVE_CONFIGURATION 0x1b
+#define SRB_SET_BRIDGE_PARMS 0x09
+#define SRB_SET_BRIDGE_TARGETS 0x10
+#define SRB_SET_FUNC_ADDRESS 0x07
+#define SRB_SET_GROUP_ADDRESS 0x06
+#define SRB_SET_GROUP_ADDR_OPTIONS 0x11
+#define SRB_UPDATE_WAKEUP_PATTERN 0x19
+
+/* Clear return code */
+
+#define OLYMPIC_CLEAR_RET_CODE 0xfe 
+
+/* ARB Commands */
+#define ARB_RECEIVE_DATA 0x81
+#define ARB_LAN_CHANGE_STATUS 0x84
+/* ASB Response commands */
+
+#define ASB_RECEIVE_DATA 0x81
+
+
+/* Olympic defaults for buffers */
+ 
+#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */
+#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */
+
+#define PKT_BUF_SZ 4096 /* Default packet size */
+
+/* Olympic data structures */
+
+struct olympic_tx_desc {
+	__u32 buffer;
+	__u32 status_length;
+};
+
+struct olympic_tx_status {
+	__u32 status;
+};
+
+struct olympic_rx_desc {
+	__u32 buffer;
+	__u32 res_length ; 
+};
+
+struct olympic_rx_status {
+	__u32 fragmentcnt_framelen;
+	__u32 status_buffercnt;
+};
+
+struct mac_receive_buffer {
+	__u16 next ; 
+	__u8 padding ; 
+	__u8 frame_status ;
+	__u16 buffer_length ; 
+	__u8 frame_data ; 
+};
+
+struct olympic_private {
+	
+	__u16 srb;
+	__u16 trb;
+	__u16 arb;
+	__u16 asb;
+
+	__u8 *olympic_mmio;
+	__u8 *olympic_lap;
+
+	volatile int srb_queued;    /* True if an SRB is still posted */	
+	wait_queue_head_t srb_wait;
+
+	volatile int asb_queued;    /* True if an ASB is posted */
+
+	volatile int trb_queued;   /* True if a TRB is posted */
+	wait_queue_head_t trb_wait ; 
+
+	struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE];
+	struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE];
+	struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE];	
+	struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE];	
+	struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE];	
+	int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries;
+
+	struct net_device_stats olympic_stats ;
+	__u16 olympic_lan_status ;
+	__u8 olympic_ring_speed ;
+	__u16 pkt_buf_sz ; 
+	__u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;  
+	__u8 olympic_multicast_set ; 
+	__u16 olympic_addr_table_addr, olympic_parms_addr ; 
+	__u8 olympic_laa[6] ; 
+};
+
+struct olympic_adapter_addr_table {
+
+	__u8 node_addr[6] ; 
+	__u8 reserved[4] ; 
+	__u8 func_addr[4] ; 
+} ; 
+
+struct olympic_parameters_table { 
+	
+	__u8  phys_addr[4] ; 
+	__u8  up_node_addr[6] ; 
+	__u8  up_phys_addr[6] ; 
+	__u8  poll_addr[6] ; 
+	__u16 reserved ; 
+	__u16 acc_priority ; 
+	__u16 auth_source_class ; 
+	__u16 att_code ; 
+	__u8  source_addr[6] ; 
+	__u16 beacon_type ; 
+	__u16 major_vector ; 
+	__u16 lan_status ; 
+	__u16 soft_error_time ; 
+ 	__u16 reserved1 ; 
+	__u16 local_ring ; 
+	__u16 mon_error ; 
+	__u16 beacon_transmit ; 
+	__u16 beacon_receive ; 
+	__u16 frame_correl ; 
+	__u8  beacon_naun[6] ; 
+	__u32 reserved2 ; 
+	__u8  beacon_phys[4] ; 	
+}; 
diff -u --recursive --new-file v2.3.9/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.3.9/linux/drivers/net/ppp.c	Wed May 12 08:41:15 1999
+++ linux/drivers/net/ppp.c	Mon Jul  5 20:35:18 1999
@@ -60,7 +60,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 #include <asm/system.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.3.9/linux/drivers/net/rtl8139.c	Sun Nov 22 09:47:52 1998
+++ linux/drivers/net/rtl8139.c	Mon Jul  5 19:56:46 1999
@@ -1,6 +1,6 @@
 /* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
 /*
-	Written 1997-1998 by Donald Becker.
+	Written 1997-1999 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -16,11 +16,11 @@
 	Support and updates available at
 	http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
 
-	Twister-tuning code contributed by Kinston <shangh@realtek.com.tw>.
+	Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
 */
 
 static const char *version =
-"rtl8139.c:v1.04 9/22/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
 
 /* A few user-configurable values. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
@@ -178,7 +178,9 @@
    0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
  { "RealTek RTL8139 Fast Ethernet",
    0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "RealTek RTL8139 Fast Ethernet (mislabeled)",
+ { "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
+   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+ { "Accton MPX5030 (RealTek RTL8139)",
    0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
  {0,},						/* 0 terminated list. */
 };
@@ -235,13 +237,13 @@
 	RxBadAlign=0x0002, RxStatusOK=0x0001,
 };
 
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links. */
 enum CSCRBits {
 	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
 	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
 	CSCR_LinkDownCmd=0x0f3c0,
-};	
-
-/* Twister tuning parameters from RealTek.  Completely undocumented. */
+};
 unsigned long param[4][4]={
 	{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
 	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
@@ -270,9 +272,10 @@
 	unsigned char *rx_ring;
 	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
 	char phys[4];						/* MII device addresses. */
+	char twistie, twist_cnt;			/* Twister tune state. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;			/* Full-duplex operation requested. */
+	unsigned int duplex_lock:1;
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	unsigned int media2:4;				/* Secondary monitored media port. */
 	unsigned int medialock:1;			/* Don't sense media type. */
@@ -325,7 +328,7 @@
 	if ( ! pcibios_present())
 		return -ENODEV;
 
-	for (;pci_index < 0xff; pci_index++) {
+	for (; pci_index < 0xff; pci_index++) {
 		u16 vendor, device, pci_command, new_command;
 		int chip_idx, irq;
 		long ioaddr;
@@ -402,9 +405,9 @@
 	return cards_found ? 0 : -ENODEV;
 }
 
-static struct device * rtl8129_probe1(int pci_bus, int pci_devfn,
-									  struct device *dev, long ioaddr,
-									  int irq, int chip_idx, int found_cnt)
+static struct device *rtl8129_probe1(int pci_bus, int pci_devfn,
+									 struct device *dev, long ioaddr,
+									 int irq, int chip_idx, int found_cnt)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct rtl8129_private *tp;
@@ -470,9 +473,8 @@
 				   dev->name);
 			tp->phys[0] = -1;
 		}
-	} else {
-			tp->phys[0] = 32;
-	}
+	} else
+		tp->phys[0] = 32;
 
 	/* Put the chip into low-power mode. */
 	outb(0xC0, ioaddr + Cfg9346);
@@ -601,7 +603,7 @@
 	int retval = 0;
 	int i;
 
-	if ((phy_id & 0x1f) == 0) {	/* Really a 8139.  Use internal registers. */
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
 		return location < 8 && mii_2_8139_map[location] ?
 			inw(dev->base_addr + mii_2_8139_map[location]) : 0;
 	}
@@ -633,7 +635,7 @@
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
 	int i;
 
-	if (phy_id == 32) {			/* Really a 8139.  Use internal registers. */
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
 		if (location < 8  &&  mii_2_8139_map[location])
 			outw(value, dev->base_addr + mii_2_8139_map[location]);
 		return;
@@ -736,7 +738,7 @@
 
 	/* Enable all known interrupts by setting the interrupt mask. */
 	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
 
 	if (rtl8129_debug > 1)
 		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
@@ -749,7 +751,7 @@
 	init_timer(&tp->timer);
 	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
 	tp->timer.data = (unsigned long)dev;
-	tp->timer.function = &rtl8129_timer;				/* timer handler */
+	tp->timer.function = &rtl8129_timer;
 	add_timer(&tp->timer);
 
 	return 0;
@@ -760,7 +762,7 @@
 	struct device *dev = (struct device *)data;
 	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int next_tick = 0;
+	int next_tick = 60*HZ;
 	int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
 
 	if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {
@@ -774,8 +776,65 @@
 			outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
 			outb(0x00, ioaddr + Cfg9346);
 		}
-		next_tick = 60*HZ;
 	}
+	/* Check for bogusness. */
+	if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
+		int status = inw(ioaddr + IntrStatus);
+		if (status & (TxOK | RxOK)) {	/* Double check */
+			printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
+				   dev->name, status);
+			rtl8129_interrupt(dev->irq, dev, 0);
+		}
+	}
+	if (dev->tbusy  &&  jiffies - dev->trans_start >= 2*TX_TIMEOUT)
+		rtl8129_tx_timeout(dev);
+
+#if 0
+	if (tp->twistie) {
+		unsigned int CSCRval = inw(ioaddr + CSCR);		/* Read link status. */
+		if (tp->twistie == 1) {
+			if (CSCRval & CSCR_LinkOKBit) {
+				outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
+				tp->twistie = 2;
+				next_tick = HZ/10;
+			} else {
+				outw(CSCR_LinkDownCmd, ioaddr + CSCR);
+				outl(FIFOTMS_default,ioaddr + FIFOTMS);
+				outl(PARA78_default ,ioaddr + PARA78);
+				outl(PARA7c_default ,ioaddr + PARA7c);
+				tp->twistie = 0;
+			}
+		} else if (tp->twistie == 2) {
+			int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12;
+			int row;
+			if (linkcase >= 0x7000) row = 3;
+			else if (linkcase >= 0x3000) row = 2;
+			else if (linkcase >= 0x1000) row = 1;
+			else row = 0;
+			tp->twistie == row + 3;
+			outw(0,ioaddr+FIFOTMS);
+			outl(param[row][0], ioaddr+PARA7c);
+			tp->twist_cnt = 1;
+		} else {
+			outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c);
+			if (++tp->twist_cnt < 4) {
+				next_tick = HZ/10;
+			} else if (tp->twistie-3 == 3) {
+				if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) {
+					outl(PARA7c_xxx, ioaddr+PARA7c);
+					next_tick = HZ/10; 		/* 100ms. */
+					outl(FIFOTMS_default, ioaddr+FIFOTMS);
+					outl(PARA78_default,  ioaddr+PARA78);
+					outl(PARA7c_default,  ioaddr+PARA7c);
+					tp->twistie == 3 + 3;
+					outw(0,ioaddr+FIFOTMS);
+					outl(param[3][0], ioaddr+PARA7c);
+					tp->twist_cnt = 1;
+				}
+			}
+		}
+	}
+#endif
 
 	if (rtl8129_debug > 2) {
 		if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
@@ -792,10 +851,8 @@
 			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
 	}
 
-	if (next_tick) {
-		tp->timer.expires = RUN_AT(next_tick);
-		add_timer(&tp->timer);
-	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
 }
 
 static void rtl8129_tx_timeout(struct device *dev)
@@ -861,7 +918,7 @@
 		}
 		tp->cur_tx = i;
 		while (i < NUM_TX_DESC)
-			tp->tx_skbuff[i] = 0;
+			tp->tx_skbuff[i++] = 0;
 		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
 			dev->tbusy = 0;
 			tp->tx_full = 0;
@@ -906,9 +963,8 @@
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		if (jiffies - dev->trans_start < TX_TIMEOUT)
-			return 1;
-		rtl8129_tx_timeout(dev);
+		if (jiffies - dev->trans_start >= TX_TIMEOUT)
+			rtl8129_tx_timeout(dev);
 		return 1;
 	}
 
@@ -925,7 +981,7 @@
 	outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
 		 ioaddr + TxStatus0 + entry*4);
 
-	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {	/* Typical path */
 		clear_bit(0, (void*)&dev->tbusy);
 	} else {
 		tp->tx_full = 1;
@@ -946,7 +1002,7 @@
 	struct device *dev = (struct device *)dev_instance;
 	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
 	int boguscnt = max_interrupt_work;
-	int status;
+	int status, link_changed = 0;
 	long ioaddr = dev->base_addr;
 
 #if defined(__i386__)
@@ -967,7 +1023,10 @@
 
 	do {
 		status = inw(ioaddr + IntrStatus);
-		/* Acknowledge all of the current interrupt sources ASAP. */
+		/* Acknowledge all of the current interrupt sources ASAP, but
+		   an first get an additional status bit from CSCR. */
+		if ((status & RxUnderrun)  &&  inw(ioaddr+CSCR) & CSCR_LinkChangeBit)
+			link_changed = 1;
 		outw(status, ioaddr + IntrStatus);
 
 		if (rtl8129_debug > 4)
@@ -982,9 +1041,9 @@
 			rtl8129_rx(dev);
 
 		if (status & (TxOK | TxErr)) {
-			unsigned int dirty_tx;
+			unsigned int dirty_tx = tp->dirty_tx;
 
-			for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
+			while (tp->cur_tx - dirty_tx > 0) {
 				int entry = dirty_tx % NUM_TX_DESC;
 				int txstatus = inl(ioaddr + TxStatus0 + entry*4);
 
@@ -994,11 +1053,9 @@
 				/* Note: TxCarrierLost is always asserted at 100mbps. */
 				if (txstatus & (TxOutOfWindow | TxAborted)) {
 					/* There was an major error, log it. */
-#ifndef final_version
 					if (rtl8129_debug > 1)
 						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
 							   dev->name, txstatus);
-#endif
 					tp->stats.tx_errors++;
 					if (txstatus&TxAborted) {
 						tp->stats.tx_aborted_errors++;
@@ -1011,9 +1068,6 @@
 						tp->stats.collisions16++;
 #endif
 				} else {
-#ifdef ETHER_STATS
-					/* No count for tp->stats.tx_deferred */
-#endif
 					if (txstatus & TxUnderrun) {
 						/* Add 64 to the Tx FIFO threshold. */
 						if (tp->tx_flag <  0x00300000)
@@ -1030,6 +1084,13 @@
 				/* Free the original skb. */
 				dev_free_skb(tp->tx_skbuff[entry]);
 				tp->tx_skbuff[entry] = 0;
+				if (tp->tx_full) {
+					/* The ring is no longer full, clear tbusy. */
+					tp->tx_full = 0;
+					clear_bit(0, (void*)&dev->tbusy);
+					mark_bh(NET_BH);
+				}
+				dirty_tx++;
 			}
 
 #ifndef final_version
@@ -1039,14 +1100,6 @@
 				dirty_tx += NUM_TX_DESC;
 			}
 #endif
-
-			if (tp->tx_full  &&  dirty_tx > tp->cur_tx - NUM_TX_DESC) {
-				/* The ring is no longer full, clear tbusy. */
-				tp->tx_full = 0;
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
-
 			tp->dirty_tx = dirty_tx;
 		}
 
@@ -1063,7 +1116,7 @@
 			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
 			outl(0, ioaddr + RxMissed);
 
-			if ((status & RxUnderrun)  &&
+			if ((status & RxUnderrun)  &&  link_changed  &&
 				(rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) {
 				/* Really link-change on new chips. */
 				int lpar = inw(ioaddr + NWayLPAR);
@@ -1284,12 +1337,12 @@
 		data[0] = tp->phys[0] & 0x3f;
 		/* Fall Through */
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+		data[3] = mdio_read(dev, data[0], data[1] & 0x1f);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser())
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -1318,7 +1371,7 @@
 {
     int crc = -1;
 
-    while(--length >= 0) {
+    while (--length >= 0) {
 		unsigned char current_octet = *data++;
 		int bit;
 		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
diff -u --recursive --new-file v2.3.9/linux/drivers/net/sealevel.c linux/drivers/net/sealevel.c
--- v2.3.9/linux/drivers/net/sealevel.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sealevel.c	Mon Jul  5 19:56:46 1999
@@ -0,0 +1,471 @@
+#define LINUX_21
+
+/*
+ *	Sealevel Systems 4021 driver.
+ *
+ *	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.
+ *
+ *	(c) Copyright 1999 Building Number Three Ltd
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <net/arp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+#include "z85230.h"
+
+
+struct slvl_device
+{
+	struct z8530_channel *chan;
+	struct ppp_device netdev;
+	char name[16];
+	int channel;
+};
+
+
+struct slvl_board
+{
+	struct slvl_device dev[2];
+	struct z8530_dev board;
+	int iobase;
+};
+
+/*
+ *	Network driver support routines
+ */
+
+/*
+ *	Frame receive. Simple for our card as we do sync ppp and there
+ *	is no funny garbage involved
+ */
+ 
+static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb)
+{
+	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
+	skb_trim(skb, skb->len-2);
+	skb->protocol=htons(ETH_P_WAN_PPP);
+	skb->mac.raw=skb->data;
+	skb->dev=c->netdevice;
+	/*
+	 *	Send it to the PPP layer. We dont have time to process
+	 *	it right now.
+	 */
+	netif_rx(skb);
+}
+ 
+/*
+ *	We've been placed in the UP state
+ */ 
+ 
+static int sealevel_open(struct device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	int err = -1;
+	int unit = slvl->channel;
+	
+	/*
+	 *	Link layer up. 
+	 */
+
+	switch(unit)
+	{
+		case 0:
+			err=z8530_sync_dma_open(d, slvl->chan);
+			break;
+		case 1:
+			err=z8530_sync_open(d, slvl->chan);
+			break;
+	}
+	
+	if(err)
+		return err;
+	/*
+	 *	Begin PPP
+	 */
+	err=sppp_open(d);
+	if(err)
+	{
+		switch(unit)
+		{
+			case 0:
+				z8530_sync_dma_close(d, slvl->chan);
+				break;
+			case 1:
+				z8530_sync_close(d, slvl->chan);
+				break;
+		}				
+		return err;
+	}
+	
+	slvl->chan->rx_function=sealevel_input;
+	
+	/*
+	 *	Go go go
+	 */
+	d->tbusy=0;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int sealevel_close(struct device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	int unit = slvl->channel;
+	
+	/*
+	 *	Discard new frames
+	 */
+	
+	slvl->chan->rx_function=z8530_null_rx;
+		
+	/*
+	 *	PPP off
+	 */
+	sppp_close(d);
+	/*
+	 *	Link layer down
+	 */
+	d->tbusy=1;
+	
+	switch(unit)
+	{
+		case 0:
+			z8530_sync_dma_close(d, slvl->chan);
+			break;
+		case 1:
+			z8530_sync_close(d, slvl->chan);
+			break;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int sealevel_ioctl(struct device *d, struct ifreq *ifr, int cmd)
+{
+	/* struct slvl_device *slvl=d->priv;
+	   z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */
+	return sppp_do_ioctl(d, ifr,cmd);
+}
+
+static struct enet_statistics *sealevel_get_stats(struct device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	if(slvl)
+		return z8530_get_stats(slvl->chan);
+	else
+		return NULL;
+}
+
+/*
+ *	Passed PPP frames, fire them downwind.
+ */
+ 
+static int sealevel_queue_xmit(struct sk_buff *skb, struct device *d)
+{
+	struct slvl_device *slvl=d->priv;
+	return z8530_queue_xmit(slvl->chan, skb);
+}
+
+#ifdef LINUX_21
+static int sealevel_neigh_setup(struct neighbour *n)
+{
+	if (n->nud_state == NUD_NONE) {
+		n->ops = &arp_broken_ops;
+		n->output = n->ops->output;
+	}
+	return 0;
+}
+
+static int sealevel_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+	if (p->tbl->family == AF_INET) {
+		p->neigh_setup = sealevel_neigh_setup;
+		p->ucast_probes = 0;
+		p->mcast_probes = 0;
+	}
+	return 0;
+}
+
+#else
+
+static int return_0(struct device *d)
+{
+	return 0;
+}
+
+#endif
+
+/*
+ *	Description block for a Comtrol Hostess SV11 card
+ */
+ 
+static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow)
+{
+	struct z8530_dev *dev;
+	struct slvl_device *sv;
+	struct slvl_board *b;
+	
+	int i;
+	unsigned long flags;
+	int u;
+	
+	/*
+	 *	Get the needed I/O space
+	 */
+	 
+	if(check_region(iobase, 8))
+	{	
+		printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase);
+		return NULL;
+	}
+	request_region(iobase, 8, "Sealevel 4021");
+	
+	b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+	if(!b)
+		goto fail3;
+			
+	memset(b, 0, sizeof(*sv));
+
+	b->dev[0].chan = &b->board.chanA;	
+	b->dev[1].chan = &b->board.chanB;
+	
+	dev=&b->board;
+	
+	/*
+	 *	Stuff in the I/O addressing
+	 */
+	 
+	dev->active = 0;
+
+	b->iobase = iobase;
+	
+	/*
+	 *	Select 8530 delays for the old board
+	 */
+	 
+	if(slow)
+		iobase |= Z8530_PORT_SLEEP;
+		
+	dev->chanA.ctrlio=iobase+1;
+	dev->chanA.dataio=iobase;
+	dev->chanB.ctrlio=iobase+3;
+	dev->chanB.dataio=iobase+2;
+	
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	
+	/*
+	 *	Assert DTR enable DMA
+	 */
+	 
+	outb(3|(1<<7), b->iobase+4);	
+	
+
+	/* We want a fast IRQ for this device. Actually we'd like an even faster
+	   IRQ ;) - This is one driver RtLinux is made for */
+   
+	if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0)
+	{
+		printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq);
+		goto fail2;
+	}
+	
+	dev->irq=irq;
+	dev->chanA.private=&b->dev[0];
+	dev->chanB.private=&b->dev[1];
+	dev->chanA.netdevice=&b->dev[0].netdev.dev;
+	dev->chanB.netdevice=&b->dev[1].netdev.dev;
+	dev->chanA.dev=dev;
+	dev->chanB.dev=dev;
+	dev->name=b->dev[0].name;
+
+	dev->chanA.txdma=3;
+	dev->chanA.rxdma=1;
+	if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0)
+		goto fail;
+		
+	if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0)
+		goto dmafail;
+	
+	save_flags(flags);
+	cli();
+	
+	/*
+	 *	Begin normal initialise
+	 */
+	 
+	if(z8530_init(dev)!=0)
+	{
+		printk(KERN_ERR "Z8530 series device not found.\n");
+		goto dmafail2;
+	}
+	if(dev->type==Z85C30)
+	{
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
+		z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream);
+	}
+	else
+	{
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
+		z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230);
+	}
+
+	/*
+	 *	Now we can take the IRQ
+	 */
+	
+	restore_flags(flags);
+
+	for(u=0; u<2; u++)
+	{
+		sv=&b->dev[u];
+		sv->channel = u;
+	
+		for(i=0;i<999;i++)
+		{
+			sprintf(sv->name,"hdlc%d", i);
+			if(dev_get(sv->name)==NULL)
+			{
+				struct device *d=sv->chan->netdevice;
+	
+				/* 
+				 *	Initialise the PPP components
+				 */
+				sppp_attach(&sv->netdev);
+			
+				/*
+				 *	Local fields
+				 */	
+				sprintf(sv->name,"hdlc%d", i);
+				
+				d->name = sv->name;
+				d->base_addr = iobase;
+				d->irq = irq;
+				d->priv = sv;
+				d->init = NULL;
+			
+				d->open = sealevel_open;
+				d->stop = sealevel_close;
+				d->hard_start_xmit = sealevel_queue_xmit;
+				d->get_stats = sealevel_get_stats;
+				d->set_multicast_list = NULL;
+				d->do_ioctl = sealevel_ioctl;
+#ifdef LINUX_21			
+				d->neigh_setup = sealevel_neigh_setup_dev;
+				dev_init_buffers(d);
+#else
+				d->init = return_0;
+#endif
+				d->set_mac_address = NULL;
+			
+				if(register_netdev(d)==-1)
+				{
+					printk(KERN_ERR "%s: unable to register device.\n",
+						sv->name);
+					goto fail_unit;
+				}				
+
+				break;
+			}
+		}
+	}
+	z8530_describe(dev, "I/O", iobase);
+	dev->active=1;
+	return b;
+
+fail_unit:
+	if(u==1)
+		unregister_netdev(b->dev[0].chan->netdevice);
+	
+dmafail2:
+	free_dma(dev->chanA.rxdma);
+dmafail:
+	free_dma(dev->chanA.txdma);
+fail:
+	free_irq(irq, dev);
+fail2:
+	kfree(b);
+fail3:
+	release_region(iobase,8);
+	return NULL;
+}
+
+static void slvl_shutdown(struct slvl_board *b)
+{
+	int u;
+
+	z8530_shutdown(&b->board);
+	
+	for(u=0; u<2; u++)
+	{
+		sppp_detach(&b->dev[u].netdev.dev);
+		unregister_netdev(&b->dev[u].netdev.dev);
+	}
+	
+	free_irq(b->board.irq, &b->board);
+	free_dma(b->board.chanA.rxdma);
+	free_dma(b->board.chanA.txdma);
+	/* DMA off on the card, drop DTR */
+	outb(0, b->iobase);
+	release_region(b->iobase, 8);
+}
+
+#ifdef MODULE
+
+static int io=0x238;
+static int txdma=1;
+static int rxdma=3;
+static int irq=5;
+static int slow=0;
+
+#ifdef LINUX_21
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io, "The I/O base of the Sealevel card");
+MODULE_PARM(txdma,"i");
+MODULE_PARM_DESC(txdma, "Transmit DMA channel");
+MODULE_PARM(rxdma,"i");
+MODULE_PARM_DESC(rxdma, "Receive DMA channel");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card");
+MODULE_PARM(slow,"i");
+MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012");
+
+MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021");
+#endif
+
+static struct slvl_board *slvl_unit;
+
+int init_module(void)
+{
+	printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n");
+	printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");	
+	if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL)
+		return -ENODEV;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if(slvl_unit)
+		slvl_shutdown(slvl_unit);
+}
+
+#endif
+
diff -u --recursive --new-file v2.3.9/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.3.9/linux/drivers/net/seeq8005.c	Tue Dec 29 11:32:06 1998
+++ linux/drivers/net/seeq8005.c	Mon Jul  5 19:56:46 1999
@@ -108,8 +108,8 @@
 struct netdev_entry seeq8005_drv =
 {"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist};
 #else
-__initfunc(int
-seeq8005_probe(struct device *dev))
+int __init 
+seeq8005_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -135,7 +135,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 seeq8005_probe1(struct device *dev, int ioaddr))
+static int __init seeq8005_probe1(struct device *dev, int ioaddr)
 {
 	static unsigned version_printed = 0;
 	int i,j;
@@ -736,6 +736,54 @@
 		outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
 }
 	
+#ifdef MODULE
+
+static char devicename[9] = { 0, };
+
+static struct device dev_seeq =
+{
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0x300, 5,
+	0, 0, 0, NULL, seeq8005_probe
+};
+
+static int io=0x320;
+static int irq=10;
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+
+int init_module(void)
+{
+	dev_seeq.irq=irq;
+	dev_seeq.base_addr=io;
+	if (register_netdev(&dev_seeq) != 0)
+		return -EIO;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	/*
+	 *	No need to check MOD_IN_USE, as sys_delete_module() checks.
+	 */
+
+	unregister_netdev(&dev_seeq);
+
+	/*
+	 *	Free up the private structure, or leak memory :-)
+	 */
+
+	kfree(dev_seeq.priv);
+	dev_seeq.priv = NULL;	/* gets re-allocated by el1_probe1 */
+
+	/*
+	 *	If we don't do this, we can't re-insmod it later.
+	 */
+	release_region(dev_seeq.base_addr, EL1_IO_EXTENT);
+}
+
+#endif /* MODULE */
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.3.9/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v2.3.9/linux/drivers/net/slhc.c	Fri Dec 18 09:40:56 1998
+++ linux/drivers/net/slhc.c	Mon Jul  5 20:35:18 1999
@@ -77,7 +77,6 @@
 #include <linux/timer.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <linux/mm.h>
 #include <linux/init.h>
 #include <net/checksum.h>
 #include <net/slhc_vj.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.3.9/linux/drivers/net/sunbmac.c	Mon Mar 15 16:11:30 1999
+++ linux/drivers/net/sunbmac.c	Mon Jul  5 20:35:18 1999
@@ -32,7 +32,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 
 #include <linux/netdevice.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.9/linux/drivers/net/sunhme.c	Thu May 27 09:55:21 1999
+++ linux/drivers/net/sunhme.c	Sun Jul  4 09:53:12 1999
@@ -3406,7 +3406,7 @@
 	/* Set the latency timer and cache line size as well,
 	 * PROM leaves it at zero.
 	 */
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
 #ifdef __sparc_v9__
 	/* NOTE: Cache line size is in 32-bit word units. */
 	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
diff -u --recursive --new-file v2.3.9/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.3.9/linux/drivers/net/sunlance.c	Sun Mar 21 07:22:00 1999
+++ linux/drivers/net/sunlance.c	Mon Jul  5 20:35:18 1999
@@ -108,7 +108,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <asm/idprom.h>
 #include <asm/machines.h>
 
 /* Define: 2^4 Tx buffers and 2^4 Rx buffers */
diff -u --recursive --new-file v2.3.9/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.3.9/linux/drivers/net/tulip.c	Tue Jan 19 13:18:45 1999
+++ linux/drivers/net/tulip.c	Mon Jul  5 19:56:46 1999
@@ -327,6 +327,10 @@
 	TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
 };
 
+enum desc_status_bits {
+	DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+        
 /* The Tulip Rx and Tx buffer descriptors. */
 struct tulip_rx_desc {
 	s32 status;
@@ -469,10 +473,12 @@
 			(PCI_CLASS_NETWORK_ETHERNET << 8,
 			 reverse_probe ? 0xfe - pci_index : pci_index,
 			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+		{
 			if (reverse_probe)
 				continue;
 			else
 				break;
+		}
 		pcibios_read_config_word(pci_bus, pci_device_fn,
 								 PCI_VENDOR_ID, &vendor);
 		pcibios_read_config_word(pci_bus, pci_device_fn,
@@ -1536,10 +1542,12 @@
 		outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
 	} else {					/* Unknown chip type with no media table. */
 		if (tp->default_port == 0)
-			if (tp->mii_cnt) {
+		{
+			if (tp->mii_cnt)
 				dev->if_port = 11;
-			} else
+			else
 				dev->if_port = 3;
+		}
 		if (media_cap[dev->if_port] & MediaIsMII) {
 			new_csr6 = 0x020E0000;
 		} else if (media_cap[dev->if_port] & MediaIsFx) {
@@ -2698,8 +2706,8 @@
 			/* Same setup recently queued, we need not add it. */
 		} else {
 			unsigned long flags;
-			unsigned int entry;
-			
+			unsigned int entry, dummy = 0;
+
 			save_flags(flags); cli();
 			entry = tp->cur_tx++ % TX_RING_SIZE;
 
@@ -2709,7 +2717,8 @@
 				tp->tx_ring[entry].length =
 					(entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
 				tp->tx_ring[entry].buffer1 = 0;
-				tp->tx_ring[entry].status = 0x80000000;
+				/* race with chip, set DescOwned later */
+				dummy = entry;
 				entry = tp->cur_tx++ % TX_RING_SIZE;
 			}
 
@@ -2724,6 +2733,8 @@
 				dev->tbusy = 1;
 				tp->tx_full = 1;
 			}
+			if (dummy >= 0)
+				tp->tx_ring[dummy].status = DescOwned;
 			restore_flags(flags);
 			/* Trigger an immediate transmit demand. */
 			outl(0, ioaddr + CSR1);
diff -u --recursive --new-file v2.3.9/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.9/linux/drivers/net/via-rhine.c	Mon May 10 13:00:10 1999
+++ linux/drivers/net/via-rhine.c	Mon Jul  5 19:56:46 1999
@@ -1,6 +1,6 @@
 /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
 /*
-	Written 1998 by Donald Becker.
+	Written 1998-1999 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License (GPL), incorporated herein by reference.
@@ -20,7 +20,7 @@
 */
 
 static const char *versionA =
-"via-rhine.c:v1.00 9/5/98  Written by Donald Becker\n";
+"via-rhine.c:v1.01 2/27/99  Written by Donald Becker\n";
 static const char *versionB =
 "  http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
 
@@ -81,9 +81,11 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-/* This driver was written to use PCI memory space, however some boards
-   only work with I/O space accesses. */
+/* This driver was written to use PCI memory space, however some x86
+   motherboards only configure I/O space accesses correctly. */
+#if defined(__i386__)  &&  !defined(VIA_USE_MEMORY)
 #define VIA_USE_IO
+#endif
 #ifdef VIA_USE_IO
 #undef readb
 #undef readw
@@ -105,6 +107,7 @@
 #define RUN_AT(x) (jiffies + (x))
 
 #if (LINUX_VERSION_CODE >= 0x20100)
+char kernel_version[] = UTS_RELEASE;
 #else
 #ifndef __alpha__
 #define ioremap vremap
@@ -502,6 +505,7 @@
 #ifndef MODULE
 int via_rhine_probe(struct device *dev)
 {
+	printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
 	return pci_etherdev_probe(dev, pci_tbl);
 }
 #endif
@@ -510,13 +514,9 @@
 								 struct device *dev, long ioaddr, int irq,
 								 int chip_id, int card_idx)
 {
-	static int did_version = 0;		/* Already printed version info */
 	struct netdev_private *np;
 	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 
-	if (debug > 0 && did_version++ == 0)
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-
 	dev = init_etherdev(dev, 0);
 
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
@@ -685,6 +685,8 @@
 		   ioaddr + IntrEnable);
 
 	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
+	if (np->duplex_lock)
+		np->chip_cmd |= CmdFDuplex;
 	writew(np->chip_cmd, ioaddr + ChipCmd);
 
 	check_duplex(dev);
@@ -1053,7 +1055,6 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			np->stats.rx_bytes += pkt_len;
 			np->stats.rx_packets++;
 		}
 		entry = (++np->cur_rx) % RX_RING_SIZE;
@@ -1182,7 +1183,7 @@
 		}
 		writel(mc_filter[0], ioaddr + MulticastFilter0);
 		writel(mc_filter[1], ioaddr + MulticastFilter1);
-		rx_mode = 0x0C;
+		rx_mode = 0x08;
 	}
 	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.3.9/linux/drivers/net/wavelan.c	Thu Apr 29 11:53:41 1999
+++ linux/drivers/net/wavelan.c	Tue Jul  6 19:08:33 1999
@@ -64,8 +64,8 @@
 /*
  * Translate PSA irq parameter to irq number 
  */
-__initfunc(static int
-wv_psa_to_irq(u_char	irqval))
+static int __init 
+wv_psa_to_irq(u_char irqval)
 {
   int	irq;
 
@@ -2087,12 +2087,6 @@
 	{
 	  struct iw_range	range;
 
-	  /* Verify the user buffer. */
-	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
-			    sizeof(struct iw_range));
-	  if(ret)
-	    break;
-
 	  /* Set the length (useless:  it's constant). */
 	  wrq->u.data.length = sizeof(struct iw_range);
 
@@ -2118,8 +2112,8 @@
 	  range.max_qual.noise = MMR_SILENCE_LVL;
 
 	  /* Copy structure to the user buffer. */
-	  copy_to_user(wrq->u.data.pointer, &range,
-		       sizeof(struct iw_range));
+	  if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
+	  	ret = -EFAULT;
 	}
       break;
 
@@ -2136,18 +2130,12 @@
 	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
 	  };
 
-	  /* Verify the user buffer. */
-	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
-			    sizeof(priv));
-	  if(ret)
-	    break;
-
 	  /* Set the number of available ioctls. */
 	  wrq->u.data.length = 4;
 
 	  /* Copy structure to the user buffer. */
-	  copy_to_user(wrq->u.data.pointer, (u_char *) priv,
-		       sizeof(priv));
+	  if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv)))
+	  	ret = -EFAULT;
 	}
       break;
 
@@ -2169,14 +2157,11 @@
 	  struct sockaddr	address[IW_MAX_SPY];
 	  int			i;
 
-	  /* Verify where the user has set his addresses. */
-	  ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
-			    sizeof(struct sockaddr) * lp->spy_number);
-	  if(ret)
-	    break;
 	  /* Copy addresses to the driver. */
-	  copy_from_user(address, wrq->u.data.pointer,
-			 sizeof(struct sockaddr) * lp->spy_number);
+	  if (copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number)) {
+	  	ret = -EFAULT;
+	  	break;
+	  }
 
 	  /* Copy addresses to the lp structure. */
 	  for(i = 0; i < lp->spy_number; i++)
@@ -2215,13 +2200,6 @@
 	  struct sockaddr	address[IW_MAX_SPY];
 	  int			i;
 
-	  /* Verify the user buffer. */
-	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
-			    (sizeof(iw_qual) + sizeof(struct sockaddr))
-			    * IW_MAX_SPY);
-	  if(ret)
-	    break;
-
 	  /* Copy addresses from the lp structure. */
 	  for(i = 0; i < lp->spy_number; i++)
 	    {
@@ -2231,13 +2209,18 @@
 	    }
 
 	  /* Copy addresses to the user buffer. */
-	  copy_to_user(wrq->u.data.pointer, address,
-		       sizeof(struct sockaddr) * lp->spy_number);
-
+	  if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number)) {
+	  	ret = -EFAULT;
+	  	break;
+	  }
+	  	
 	  /* Copy stats to the user buffer (just after). */
-	  copy_to_user(wrq->u.data.pointer +
+	  if (copy_to_user(wrq->u.data.pointer +
 		       (sizeof(struct sockaddr) * lp->spy_number),
-		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
+		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) {
+		       		ret = -EFAULT;
+		       		break;
+	  }
 
 	  /* Reset updated flags. */
 	  for(i = 0; i < lp->spy_number; i++)
@@ -2283,14 +2266,11 @@
       /* Are there addresses to copy? */
       if(lp->his_number > 0)
 	{
-	  /* Verify where the user has set his addresses. */
-	  ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
-			    sizeof(char) * lp->his_number);
-	  if(ret)
-	    break;
 	  /* Copy interval ranges to the driver */
-	  copy_from_user(lp->his_range, wrq->u.data.pointer,
-			 sizeof(char) * lp->his_number);
+	  if (copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number)) {
+	  	ret = -EFAULT;
+	  	break;
+	  }
 
 	  /* Reset structure. */
 	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
@@ -2304,15 +2284,10 @@
       /* Give back the distribution statistics */
       if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
 	{
-	  /* Verify the user buffer. */
-	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
-			    sizeof(long) * 16);
-	  if(ret)
-	    break;
-
 	  /* Copy data to the user buffer. */
-	  copy_to_user(wrq->u.data.pointer, lp->his_sum,
-		       sizeof(long) * lp->his_number);
+	  if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number)) 
+			ret = -EFAULT;
+			
 	}	/* if(pointer != NULL) */
       break;
 #endif	/* HISTOGRAM */
@@ -4015,8 +3990,8 @@
  * device structure
  * (called by wavelan_probe() and via init_module()).
  */
-__initfunc(static int
-wavelan_config(device *	dev))
+static int __init 
+wavelan_config(device *	dev)
 {
   u_long	ioaddr = dev->base_addr;
   u_char	irq_mask;
@@ -4132,8 +4107,8 @@
  * We follow the example in drivers/net/ne.c.
  * (called in "Space.c")
  */
-__initfunc(int
-wavelan_probe(device *	dev))
+int __init 
+wavelan_probe(device *	dev)
 {
   short		base_addr;
   mac_addr	mac;		/* MAC address (check existence of WaveLAN) */
@@ -4265,6 +4240,11 @@
 
 	  /* Create device and set basic arguments. */
 	  dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+	  if(dev==NULL)
+	  {
+	  	ret = -ENOMEM;
+	  	break;
+	  }
 	  memset(dev, 0x00, sizeof(struct device));
 	  dev->name = name[i];
 	  dev->base_addr = io[i];
diff -u --recursive --new-file v2.3.9/linux/drivers/net/z85230.c linux/drivers/net/z85230.c
--- v2.3.9/linux/drivers/net/z85230.c	Sat Apr 24 17:51:48 1999
+++ linux/drivers/net/z85230.c	Mon Jul  5 19:56:46 1999
@@ -23,7 +23,8 @@
  *	Z85230:
  *	Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud
  *	X.25 is not unrealistic on all machines. DMA mode can in theory
- *	handle T1/E1 quite nicely.
+ *	handle T1/E1 quite nicely. In practice the limit seems to be about
+ *	512Kbit->1Mbit depending on motherboard.
  *
  *	Z85C30:
  *	64K will take DMA, 9600 baud X.25 should be ok.
@@ -187,7 +188,6 @@
 	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
 	9,	NV|MIE|NORESET,
 	23,	3,		/* Extended mode AUTO TX and EOM*/
-	31,	3,		/* Extended mode AUTO TX and EOM*/
 	
 	255
 };
@@ -834,6 +834,8 @@
 
 int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c)
 {
+	unsigned long flags;
+
 	printk("Opening sync interface for TX-DMA\n");
 	c->sync = 1;
 	c->mtu = dev->mtu+64;
@@ -889,14 +891,21 @@
 	c->regs[R14]|= DTRREQ;
 	write_zsreg(c, R14, c->regs[R14]);     
 	
+	c->regs[R1]&= ~TxINT_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);
+	
 	/*
 	 *	Set up the DMA configuration
 	 */	
 	 
+	flags = claim_dma_lock();
+
 	disable_dma(c->txdma);
 	clear_dma_ff(c->txdma);
 	set_dma_mode(c->txdma, DMA_MODE_WRITE);
 	disable_dma(c->txdma);
+
+	release_dma_lock(flags);
 	
 	/*
 	 *	Select the DMA interrupt handlers
@@ -918,6 +927,7 @@
 	
 int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c)
 {
+	unsigned long flags;
 	u8 chk;
 	c->irqs = &z8530_nop;
 	c->max = 0;
@@ -927,10 +937,14 @@
 	 *	Disable the PC DMA channels
 	 */
 	 
+	flags = claim_dma_lock();
+
 	disable_dma(c->txdma);
 	clear_dma_ff(c->txdma);
 	c->txdma_on = 0;
 	c->tx_dma_used = 0;
+
+	release_dma_lock(flags);
 
 	/*
 	 *	Disable DMA control mode
diff -u --recursive --new-file v2.3.9/linux/drivers/net/zlib.c linux/drivers/net/zlib.c
--- v2.3.9/linux/drivers/net/zlib.c	Tue Feb 10 12:56:45 1998
+++ linux/drivers/net/zlib.c	Mon Jul  5 20:35:18 1999
@@ -5113,10 +5113,6 @@
 
 /* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
 
-#ifdef DEBUG_ZLIB
-#include <stdio.h>
-#endif
-
 /* #include "zutil.h" */
 
 #ifndef NO_DUMMY_DECL
diff -u --recursive --new-file v2.3.9/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.3.9/linux/drivers/pci/oldproc.c	Wed Jun  9 16:59:15 1999
+++ linux/drivers/pci/oldproc.c	Thu Jul  8 14:50:20 1999
@@ -263,6 +263,7 @@
 	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"),
@@ -308,6 +309,7 @@
 	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"),
@@ -465,6 +467,7 @@
 	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"),
@@ -503,6 +506,7 @@
 	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"),
@@ -541,6 +545,7 @@
 	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"),
@@ -831,6 +836,7 @@
 	      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";
@@ -1027,7 +1033,7 @@
 	0, &proc_array_inode_operations
 };
 
-__initfunc(void proc_old_pci_init(void))
+void __init proc_old_pci_init(void)
 {
 	proc_register(&proc_root, &proc_old_pci);
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.9/linux/drivers/pci/pci.c	Sat Jun 19 18:20:13 1999
+++ linux/drivers/pci/pci.c	Mon Jul  5 19:56:46 1999
@@ -138,7 +138,7 @@
 	}
 }
 
-__initfunc(void pci_read_bases(struct pci_dev *dev, unsigned int howmany))
+void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany)
 {
 	unsigned int reg;
 	u32 l;
@@ -166,7 +166,7 @@
 }
 
 
-__initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
+unsigned int __init pci_scan_bus(struct pci_bus *bus)
 {
 	unsigned int devfn, l, max, class;
 	unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
@@ -192,6 +192,11 @@
 			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;
@@ -300,6 +305,11 @@
 			 * 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;
@@ -389,7 +399,7 @@
 	return b;
 }
 
-__initfunc(void pci_init(void))
+void __init pci_init(void)
 {
 	pcibios_init();
 
@@ -415,7 +425,7 @@
 #endif
 }
 
-__initfunc(void pci_setup (char *str, int *ints))
+void __init pci_setup (char *str, int *ints)
 {
 	while (str) {
 		char *k = strchr(str, ',');
diff -u --recursive --new-file v2.3.9/linux/drivers/pnp/Config.in linux/drivers/pnp/Config.in
--- v2.3.9/linux/drivers/pnp/Config.in	Wed Jul 23 11:14:31 1997
+++ linux/drivers/pnp/Config.in	Thu Jul  1 14:22:57 1999
@@ -1,16 +1,3 @@
 #
 # Plug and Play configuration
 #
-
-mainmenu_option next_comment
-comment 'Plug and Play support'
- 
-bool 'Plug and Play support' CONFIG_PNP
-
-if [ "$CONFIG_PNP" = "y" ]; then
-  if [ "$CONFIG_PARPORT" != "n" ]; then
-    dep_tristate '  Auto-probe for parallel devices' CONFIG_PNP_PARPORT $CONFIG_PARPORT
-  fi
-fi
-
-endmenu
diff -u --recursive --new-file v2.3.9/linux/drivers/pnp/Makefile linux/drivers/pnp/Makefile
--- v2.3.9/linux/drivers/pnp/Makefile	Wed Jul 23 11:14:31 1997
+++ linux/drivers/pnp/Makefile	Thu Jul  1 14:22:57 1999
@@ -7,10 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes..
-#
-# Note 3! Plug and Play is the Borg.  We have assimilated some other
-# drivers in the `char', `net' and `scsi' directories, but left them
-# there to allay suspicion.
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
@@ -21,13 +17,5 @@
 LX_OBJS  := 
 MI_OBJS  :=
 MIX_OBJS :=
-
-ifeq ($(CONFIG_PNP_PARPORT),y)
-  LX_OBJS += parport_probe.o
-else
-  ifeq ($(CONFIG_PNP_PARPORT),m)
-    MX_OBJS += parport_probe.o
-  endif
-endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.9/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c
--- v2.3.9/linux/drivers/pnp/parport_probe.c	Wed Jan 20 13:29:18 1999
+++ linux/drivers/pnp/parport_probe.c	Wed Dec 31 16:00:00 1969
@@ -1,288 +0,0 @@
-/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $ 
- * Parallel port device probing code
- * 
- * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- *             Philip Blundell <Philip.Blundell@pobox.com>
- */
-
-#include <linux/tasks.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-
-#include <linux/lp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#undef DEBUG_PROBE
-
-static inline int read_nibble(struct parport *port) 
-{
-	unsigned char i;
-	i = parport_read_status(port)>>3;
-	i &= ~8;
-	if ((i & 0x10) == 0) i |= 8;
-	return (i & 0x0f);
-}
-
-static void read_terminate(struct parport *port) {
-	parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-	/* SelectIN high, AutoFeed low */
-	if (parport_wait_peripheral(port, 0x80, 0)) 
-		/* timeout, SelectIN high, Autofeed low */
-		return;
-	parport_write_control(port, parport_read_control(port) | 2);
-	/* AutoFeed high */
-	parport_wait_peripheral(port, 0x80, 0x80);
-	/* no timeout possible, Autofeed low, SelectIN high */
-	parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-}
-
-static long read_polled(struct parport *port, char *buf, 
-			   unsigned long length)
-{
-	int i;
-	char *temp=buf;
-	unsigned int count = 0;
-	unsigned char z=0;
-	unsigned char Byte=0;
-	unsigned long igiveupat=jiffies+5*HZ;
-
-	for (i=0; time_before(jiffies, igiveupat); i++) {
-	       /* if(current->need_resched) schedule(); */
-		parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */
-		if (parport_wait_peripheral(port, 0x40, 0)) {
-#ifdef DEBUG_PROBE
-			/* Some peripherals just time out when they've sent
-			   all their data.  */
-			printk("%s: read1 timeout.\n", port->name);
-#endif
-			parport_write_control(port, parport_read_control(port) & ~2);
-			break;
-		}
-		z = read_nibble(port);
-		parport_write_control(port, parport_read_control(port) & ~2); /* AutoFeed low */
-		if (parport_wait_peripheral(port, 0x40, 0x40)) {
-			printk("%s: read2 timeout.\n", port->name);
-			break;
-		}
-		if ((i & 1) != 0) {
-			Byte |= (z<<4);
-			if (temp) 
-				*(temp++) = Byte; 
-			if (++count == length)
-				temp = NULL;
-			/* Does the error line indicate end of data? */
-			if ((parport_read_status(port) & LP_PERRORP) == 
-			    LP_PERRORP) 
-				break;
-		} else 
-			Byte=z;
-	}
-	read_terminate(port);
-	return count; 
-}
-
-int parport_probe(struct parport *port, char *buffer, int len)
-{
-	struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev);
-
-	int result = 0;
-
-	if (!dev) {
-		printk("%s: unable to register for probe.\n", port->name);
-		return -EINVAL;
-	}
-
-	parport_claim_or_block(dev);
-
-	switch (parport_ieee1284_nibble_mode_ok(port, 4)) {
-	case 2:
-		current->state=TASK_INTERRUPTIBLE;
-		/* HACK: wait 10ms because printer seems to ack wrong */
-		schedule_timeout((HZ+99)/100);	
-		result = read_polled(port, buffer, len);
-		break;
-	default:
-		result = -EIO;
-		break;
-	}
-
-	parport_release(dev);
-	parport_unregister_device(dev);
-
-	return result;
-}
-
-static struct {
-	char *token;
-	char *descr;
-} classes[] = {
-	{ "",        "Legacy device" },
-	{ "PRINTER", "Printer" }, 
-	{ "MODEM",   "Modem" },
-	{ "NET",     "Network device" },
-	{ "HDC",     "Hard disk" },
-	{ "PCMCIA",  "PCMCIA" },
-	{ "MEDIA",   "Multimedia device" },
-	{ "FDC",     "Floppy disk" },
-	{ "PORTS",   "Ports" },
-	{ "SCANNER", "Scanner" },
-	{ "DIGICAM", "Digital camera" },
-	{ "",        "Unknown device" },
-	{ "",        "Unspecified" }, 
-	{ NULL,      NULL }
-};
-
-static char *strdup(char *str)
-{
-	int n = strlen(str)+1;
-	char *s = kmalloc(n, GFP_KERNEL);
-	if (!s) return NULL;
-	return strcpy(s, str);
-}
-
-static void parse_data(struct parport *port, char *str)
-{
-	char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
-	char *p = txt, *q; 
-	int guessed_class = PARPORT_CLASS_UNSPEC;
-
-	if (!txt) {
-		printk("%s probe: memory squeeze\n", port->name);
-		return;
-	}
-	strcpy(txt, str);
-	while (p) {
-		char *sep; 
-		q = strchr(p, ';');
-		if (q) *q = 0;
-		sep = strchr(p, ':');
-		if (sep) {
-			char *u = p;
-			*(sep++) = 0;
-			while (*u) {
-				*u = toupper(*u);
-				u++;
-			}
-			if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
-				if (port->probe_info.mfr)
-					kfree (port->probe_info.mfr);
-				port->probe_info.mfr = strdup(sep);
-			} else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
-				if (port->probe_info.model)
-					kfree (port->probe_info.model);
-				port->probe_info.model = strdup(sep);
-			} else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
-				int i;
-				if (port->probe_info.class_name)
-					kfree (port->probe_info.class_name);
-				port->probe_info.class_name = strdup(sep);
-				for (u = sep; *u; u++)
-					*u = toupper(*u);
-				for (i = 0; classes[i].token; i++) {
-					if (!strcmp(classes[i].token, sep)) {
-						port->probe_info.class = i;
-						goto rock_on;
-					}
-				}
-				printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
-				port->probe_info.class = PARPORT_CLASS_OTHER;
-			} else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) {
-				if (port->probe_info.cmdset)
-					kfree (port->probe_info.cmdset);
-				port->probe_info.cmdset = strdup(sep);
-				/* if it speaks printer language, it's
-				   probably a printer */
-				if (strstr(sep, "PJL") || strstr(sep, "PCL"))
-					guessed_class = PARPORT_CLASS_PRINTER;
-			} else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
-				if (port->probe_info.description)
-					kfree (port->probe_info.description);
-				port->probe_info.description = strdup(sep);
-			}
-		}
-	rock_on:
-		if (q) p = q+1; else p=NULL;
-	}
-
-	/* If the device didn't tell us its class, maybe we have managed to
-	   guess one from the things it did say. */
-	if (port->probe_info.class == PARPORT_CLASS_UNSPEC)
-		port->probe_info.class = guessed_class;
-
-	kfree(txt);
-}
-
-static void pretty_print(struct parport *port)
-{
-	printk(KERN_INFO "%s: %s", port->name,
-	       classes[port->probe_info.class].descr);
-	if (port->probe_info.class) {
-		printk(", %s %s", port->probe_info.mfr, 
-		       port->probe_info.model);
-	}
-	printk("\n");
-}
-
-void parport_probe_one(struct parport *port)
-{
-	char *buffer = kmalloc(2048, GFP_KERNEL);
-	int r;
-
-	MOD_INC_USE_COUNT;
-	port->probe_info.model = strdup ("Unknown device");
-	port->probe_info.mfr = strdup ("Unknown vendor");
-	port->probe_info.description = port->probe_info.cmdset = NULL;
-	port->probe_info.class = PARPORT_CLASS_UNSPEC;
-	port->probe_info.class_name = NULL;
-
-	if (!buffer) {
-		printk(KERN_ERR "%s probe: Memory squeeze.\n", port->name);
-		return;
-	}
-
-	r = parport_probe(port, buffer, 2047);
-
-	if (r < 0) {
-		printk(KERN_INFO "%s: no IEEE-1284 device present.\n",
-		       port->name);
-		port->probe_info.class = PARPORT_CLASS_LEGACY;
-	} else if (r == 0) {
-		printk(KERN_INFO "%s: no ID data returned by device.\n",
-		       port->name);
-	} else {
-		buffer[r] = 0; 
-#ifdef DEBUG_PROBE
-		printk("%s id: %s\n", port->name, buffer+2);
-#endif
-		parse_data(port, buffer+2); 
-		pretty_print(port);
-	}
-	kfree(buffer);
-	MOD_DEC_USE_COUNT;
-}
-
-#if MODULE
-int init_module(void)
-{
-	struct parport *p;
-	for (p = parport_enumerate(); p; p = p->next) 
-		parport_probe_one(p);
-	parport_probe_hook = &parport_probe_one;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	parport_probe_hook = NULL;
-}
-#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.3.9/linux/drivers/sbus/char/bpp.c	Wed Jun  9 14:44:25 1999
+++ linux/drivers/sbus/char/bpp.c	Mon Jul  5 20:35:18 1999
@@ -20,10 +20,10 @@
 #include <linux/ioport.h>
 #include <linux/major.h>
 
-#include  <asm/uaccess.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
 
 #if defined(__i386__)
-# include <asm/io.h>
 # include <asm/system.h>
 # include <asm/segment.h>
 #endif
@@ -34,7 +34,6 @@
 
 # include <asm/oplib.h>           /* OpenProm Library */
 # include <asm/sbus.h>            /* struct linux_sbus *SBus_chain */
-# include <asm/io.h>              /* sparc_alloc_io() */
 #endif
 
 #include <asm/bpp.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.3.9/linux/drivers/sbus/char/sab82532.c	Wed May 12 08:41:15 1999
+++ linux/drivers/sbus/char/sab82532.c	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.31 1999/05/12 11:15:10 davem Exp $
+/* $Id: sab82532.c,v 1.32 1999/07/03 08:57:41 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -1672,7 +1672,6 @@
 #endif
 	while (info->xmit_cnt || !info->all_sent) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
@@ -2136,7 +2135,7 @@
 
 __initfunc(static inline void show_serial_version(void))
 {
-	char *revision = "$Revision: 1.31 $";
+	char *revision = "$Revision: 1.32 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.3.9/linux/drivers/sbus/char/su.c	Thu Jun 17 01:08:50 1999
+++ linux/drivers/sbus/char/su.c	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.21 1999/06/11 10:23:42 davem Exp $
+/* $Id: su.c,v 1.22 1999/07/03 08:57:43 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -1836,7 +1836,6 @@
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
@@ -2215,7 +2214,7 @@
  */
 __initfunc(static __inline__ void show_su_version(void))
 {
-	char *revision = "$Revision: 1.21 $";
+	char *revision = "$Revision: 1.22 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.3.9/linux/drivers/sbus/sbus.c	Mon May 31 22:08:10 1999
+++ linux/drivers/sbus/sbus.c	Mon Jul  5 20:35:18 1999
@@ -8,7 +8,6 @@
 #include <linux/malloc.h>
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/malloc.h>
 #include <linux/pci.h>
 
 #include <asm/system.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.3.9/linux/drivers/scsi/53c7xx.c	Mon Oct  5 13:43:31 1998
+++ linux/drivers/scsi/53c7xx.c	Mon Jul  5 20:35:18 1999
@@ -254,9 +254,9 @@
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <asm/spinlock.h>
+#include <asm/pgtable.h>
 
 #ifdef CONFIG_AMIGA
-#include <asm/pgtable.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
@@ -266,7 +266,6 @@
 #endif
 
 #ifdef CONFIG_MVME16x
-#include <asm/pgtable.h>
 #include <asm/mvme16xhw.h>
 
 #define BIG_ENDIAN
@@ -275,7 +274,6 @@
 #endif
 
 #ifdef CONFIG_BVME6000
-#include <asm/pgtable.h>
 #include <asm/bvme6000hw.h>
 
 #define BIG_ENDIAN
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c
--- v2.3.9/linux/drivers/scsi/NCR53C9x.c	Fri Dec 18 09:47:38 1998
+++ linux/drivers/scsi/NCR53C9x.c	Mon Jul  5 19:56:46 1999
@@ -3390,6 +3390,7 @@
 	struct ESP_regs *eregs;
 	Scsi_Cmnd *SCptr;
 	int what_next = do_intr_end;
+	unsigned long flags;
 #ifdef CONFIG_SCSI_SUNESP
 	struct sparc_dma_registers *dregs = 
 	  (struct sparc_dma_registers*) esp->dregs;
@@ -3610,7 +3611,9 @@
 			}
 			SCptr->result = (DID_RESET << 16);
 
+			spin_lock_irqsave(&io_request_lock,flags);
 			SCptr->scsi_done(SCptr);
+			spin_unlock_irqrestore(&io_request_lock, flags);
 		}
 		esp->current_SC = NULL;
 		if(esp->disconnected_SC) {
@@ -3625,7 +3628,9 @@
 				}
 				SCptr->result = (DID_RESET << 16);
 
+				spin_lock_irqsave(&io_request_lock,flags);
 				SCptr->scsi_done(SCptr);
+				spin_unlock_irqrestore(&io_request_lock, flags);
 			}
 		}
 		esp->resetting_bus = 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.3.9/linux/drivers/scsi/aha152x.c	Wed May 12 13:19:17 1999
+++ linux/drivers/scsi/aha152x.c	Tue Jul  6 19:08:33 1999
@@ -183,7 +183,7 @@
  **************************************************************************
 
 
- 
+
  DESCRIPTION:
 
  This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI
@@ -192,30 +192,30 @@
 
  CONFIGURATION ARGUMENTS:
 
-  IOPORT        base io address                           (0x340/0x140)
-  IRQ           interrupt level                           (9-12; default 11)
-  SCSI_ID       scsi id of controller                     (0-7; default 7)
-  RECONNECT     allow targets to disconnect from the bus  (0/1; default 1 [on])
-  PARITY        enable parity checking                    (0/1; default 1 [on])
-  SYNCHRONOUS   enable synchronous transfers              (0/1; default 0 [off])
-                (NOT WORKING YET)
-  DELAY:        bus reset delay                           (default 100)
-  EXT_TRANS:    enable extended translation               (0/1: default 0 [off])
-                (see NOTES below)
+ IOPORT        base io address                           (0x340/0x140)
+ IRQ           interrupt level                           (9-12; default 11)
+ SCSI_ID       scsi id of controller                     (0-7; default 7)
+ RECONNECT     allow targets to disconnect from the bus  (0/1; default 1 [on])
+ PARITY        enable parity checking                    (0/1; default 1 [on])
+ SYNCHRONOUS   enable synchronous transfers              (0/1; default 0 [off])
+ (NOT WORKING YET)
+ DELAY:        bus reset delay                           (default 100)
+ EXT_TRANS:    enable extended translation               (0/1: default 0 [off])
+ (see NOTES below)
 
  COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile):
 
  -DAUTOCONF
-   use configuration the controller reports (AHA-152x only)
+ use configuration the controller reports (AHA-152x only)
 
  -DSKIP_BIOSTEST
-   Don't test for BIOS signature (AHA-1510 or disabled BIOS)
+ Don't test for BIOS signature (AHA-1510 or disabled BIOS)
 
  -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
-   override for the first controller 
-   
+ override for the first controller 
+
  -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
-   override for the second controller
+ override for the second controller
 
 
  LILO COMMAND LINE OPTIONS:
@@ -230,13 +230,13 @@
 
 
  SYMBOLS FOR MODULE CONFIGURATION:
- 
-  aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
-    configuration override of first controller
-
- 
-  aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
-    configuration override of second controller
+
+ aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
+ configuration override of first controller
+
+
+ aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
+ configuration override of second controller
 
 
  NOTES ON EXT_TRANS: 
@@ -287,14 +287,14 @@
 
  - for disks<1GB: use default translation (C/32/64)
  - for disks>1GB:
-   - take current geometry from the partition table
-     (using scsicam_bios_param and accept only `valid' geometries,
-      ie. either (C/32/64) or (C/63/255)).  This can be extended
-      translation even if it's not enabled in the driver.
-   - if that fails, take extended translation if enabled by override,
-     kernel or module parameter, otherwise take default translation and
-     ask the user for verification.  This might on not yet partitioned
-     disks or
+ - take current geometry from the partition table
+ (using scsicam_bios_param and accept only `valid' geometries,
+ ie. either (C/32/64) or (C/63/255)).  This can be extended
+ translation even if it's not enabled in the driver.
+ - if that fails, take extended translation if enabled by override,
+ kernel or module parameter, otherwise take default translation and
+ ask the user for verification.  This might on not yet partitioned
+ disks or
 
 
  REFERENCES USED:
@@ -308,7 +308,7 @@
  "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
 
  "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
- 
+
  Michael K. Johnson (johnsonm@sunsite.unc.edu)
 
  Drew Eckhardt (drew@cs.colorado.edu)
@@ -350,9 +350,10 @@
 
 #include <scsi/scsicam.h>
 
-struct proc_dir_entry proc_scsi_aha152x = {
-    PROC_SCSI_AHA152X, 7, "aha152x",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
+struct proc_dir_entry proc_scsi_aha152x =
+{
+	PROC_SCSI_AHA152X, 7, "aha152x",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
 /* DEFINES */
@@ -370,25 +371,25 @@
 
 #if defined(DEBUG_AHA152X)
 
-#undef  SKIP_PORTS              /* don't display ports */
+#undef  SKIP_PORTS		/* don't display ports */
 
-#undef  DEBUG_QUEUE             /* debug queue() */
-#undef  DEBUG_RESET             /* debug reset() */
-#undef  DEBUG_INTR              /* debug intr() */
-#undef  DEBUG_SELECTION         /* debug selection part in intr() */
-#undef  DEBUG_MSGO              /* debug message out phase in intr() */
-#undef  DEBUG_MSGI              /* debug message in phase in intr() */
-#undef  DEBUG_STATUS            /* debug status phase in intr() */
-#undef  DEBUG_CMD               /* debug command phase in intr() */
-#undef  DEBUG_DATAI             /* debug data in phase in intr() */
-#undef  DEBUG_DATAO             /* debug data out phase in intr() */
-#undef  DEBUG_ABORT             /* debug abort() */
-#undef  DEBUG_DONE              /* debug done() */
-#undef  DEBUG_BIOSPARAM         /* debug biosparam() */
-
-#undef  DEBUG_RACE              /* debug race conditions */
-#undef  DEBUG_PHASES            /* debug phases (useful to trace) */
-#undef  DEBUG_QUEUES            /* debug reselection */
+#undef  DEBUG_QUEUE		/* debug queue() */
+#undef  DEBUG_RESET		/* debug reset() */
+#undef  DEBUG_INTR		/* debug intr() */
+#undef  DEBUG_SELECTION		/* debug selection part in intr() */
+#undef  DEBUG_MSGO		/* debug message out phase in intr() */
+#undef  DEBUG_MSGI		/* debug message in phase in intr() */
+#undef  DEBUG_STATUS		/* debug status phase in intr() */
+#undef  DEBUG_CMD		/* debug command phase in intr() */
+#undef  DEBUG_DATAI		/* debug data in phase in intr() */
+#undef  DEBUG_DATAO		/* debug data out phase in intr() */
+#undef  DEBUG_ABORT		/* debug abort() */
+#undef  DEBUG_DONE		/* debug done() */
+#undef  DEBUG_BIOSPARAM		/* debug biosparam() */
+
+#undef  DEBUG_RACE		/* debug race conditions */
+#undef  DEBUG_PHASES		/* debug phases (useful to trace) */
+#undef  DEBUG_QUEUES		/* debug reselection */
 
 /* recently used for debugging */
 #if 0
@@ -424,46 +425,50 @@
 #define IRQS    IRQ_MAX-IRQ_MIN+1
 
 enum {
-  not_issued   = 0x0001,
-  in_selection = 0x0002,
-  disconnected = 0x0004,
-  aborted      = 0x0008,
-  sent_ident   = 0x0010,
-  in_other     = 0x0020,
-  in_sync      = 0x0040,
-  sync_ok      = 0x0080,
+	not_issued = 0x0001,
+	in_selection = 0x0002,
+	disconnected = 0x0004,
+	aborted = 0x0008,
+	sent_ident = 0x0010,
+	in_other = 0x0020,
+	in_sync = 0x0040,
+	sync_ok = 0x0080,
 };
 
 #if defined(MODULE)
 #if defined(DEBUG_AHA152X)
-int aha152x[]  = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT };
-int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT };
+int aha152x[] =
+{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+int aha152x1[] =
+{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
 MODULE_PARM(aha152x, "1-9i");
 MODULE_PARM(aha152x1, "1-9i");
 #else
-int aha152x[]  = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 };
-int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 };
+int aha152x[] =
+{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+int aha152x1[] =
+{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
 MODULE_PARM(aha152x, "1-8i");
 MODULE_PARM(aha152x1, "1-8i");
 #endif
 #endif
 
 /* set by aha152x_setup according to the command line */
-static int  setup_count=0;
-static int  registered_count=0;
+static int setup_count = 0;
+static int registered_count = 0;
 static struct aha152x_setup {
-  int io_port;
-  int irq;
-  int scsiid;
-  int reconnect;
-  int parity;
-  int synchronous;
-  int delay;
-  int ext_trans;
+	int io_port;
+	int irq;
+	int scsiid;
+	int reconnect;
+	int parity;
+	int synchronous;
+	int delay;
+	int ext_trans;
 #ifdef DEBUG_AHA152X
-  int debug;
+	int debug;
 #endif
-  char *conf;
+	char *conf;
 } setup[2];
 
 static struct Scsi_Host *aha152x_host[IRQS];
@@ -480,30 +485,30 @@
 #define ADDMSG(x)         (MSG(MSGLEN++)=x)
 
 struct aha152x_hostdata {
-  Scsi_Cmnd     *issue_SC;
-  Scsi_Cmnd     *current_SC;
-  Scsi_Cmnd     *disconnected_SC;
-  int           aborting;
-  int           abortion_complete;
-  int           abort_result;
-  int           commands;
-  
-  int           reconnect;
-  int           parity;
-  int           synchronous;
-  int           delay;
-  int           ext_trans;
-
-  int           swint;
-  int		service;
- 
-  unsigned char syncrate[8];
-  
-  unsigned char message[256];
-  int           message_len;
+	Scsi_Cmnd *issue_SC;
+	Scsi_Cmnd *current_SC;
+	Scsi_Cmnd *disconnected_SC;
+	int aborting;
+	int abortion_complete;
+	int abort_result;
+	int commands;
+
+	int reconnect;
+	int parity;
+	int synchronous;
+	int delay;
+	int ext_trans;
+
+	int swint;
+	int service;
+
+	unsigned char syncrate[8];
+
+	unsigned char message[256];
+	int message_len;
 
 #ifdef DEBUG_AHA152X
-  int           debug;
+	int debug;
 #endif
 };
 
@@ -516,7 +521,7 @@
 static void aha152x_panic(struct Scsi_Host *shpnt, char *msg);
 
 static void disp_ports(struct Scsi_Host *shpnt);
-static void show_command(Scsi_Cmnd *ptr);
+static void show_command(Scsi_Cmnd * ptr);
 static void show_queues(struct Scsi_Host *shpnt);
 static void disp_enintr(struct Scsi_Host *shpnt);
 
@@ -528,8 +533,8 @@
 /* possible i/o addresses for the AIC-6260 */
 static unsigned short ports[] =
 {
-  0x340,      /* default first */
-  0x140
+	0x340,			/* default first */
+	0x140
 };
 #define PORT_COUNT (sizeof(ports) / sizeof(unsigned short))
 
@@ -537,15 +542,15 @@
 /* possible locations for the Adaptec BIOS */
 static unsigned int addresses[] =
 {
-  0xdc000,   /* default first */
-  0xc8000,
-  0xcc000,
-  0xd0000,
-  0xd4000,
-  0xd8000,
-  0xe0000,
-  0xeb800,   /* VTech Platinum SMP */
-  0xf0000,
+	0xdc000,		/* default first */
+	0xc8000,
+	0xcc000,
+	0xd0000,
+	0xd4000,
+	0xd8000,
+	0xe0000,
+	0xeb800,		/* VTech Platinum SMP */
+	0xf0000,
 };
 #define ADDRESS_COUNT (sizeof(addresses) / sizeof(unsigned int))
 
@@ -557,80 +562,103 @@
    needed anyway.  May be an information whether or not the BIOS supports
    extended translation could be also useful here. */
 static struct signature {
-  unsigned char *signature;
-  int  sig_offset;
-  int  sig_length;
+	unsigned char *signature;
+	int sig_offset;
+	int sig_length;
 } signatures[] =
+
 {
-  { "Adaptec AHA-1520 BIOS",      0x102e, 21 },  /* Adaptec 152x */
-  { "Adaptec AHA-1520B",            0x0b, 19 },  /* Adaptec 152x rev B */
-  { "Adaptec ASW-B626 BIOS",      0x1029, 21 },  /* on-board controller */
-  { "Adaptec BIOS: ASW-B626",       0x0f, 22 },  /* on-board controller */
-  { "Adaptec ASW-B626 S2",        0x2e6c, 19 },  /* on-board controller */
-  { "Adaptec BIOS:AIC-6360",         0xc, 21 },  /* on-board controller */
-  { "ScsiPro SP-360 BIOS",        0x2873, 19 },  /* ScsiPro-Controller  */
-  { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },  /* Gigabyte Local-Bus-SCSI */
-  { "Adaptec BIOS:AVA-282X",         0xc, 21 },  /* Adaptec 282x */
-  { "Adaptec IBM Dock II SCSI",   0x2edd, 24 },  /* IBM Thinkpad Dock II */
-  { "Adaptec BIOS:AHA-1532P",       0x1c, 22 },  /* IBM Thinkpad Dock II SCSI */
-  { "DTC3520A Host Adapter BIOS", 0x318a, 26 },  /* DTC 3520A ISA SCSI */
+	{
+		"Adaptec AHA-1520 BIOS", 0x102e, 21
+	},			/* Adaptec 152x */
+	{
+		"Adaptec AHA-1520B", 0x0b, 19
+	},			/* Adaptec 152x rev B */
+	{
+		"Adaptec ASW-B626 BIOS", 0x1029, 21
+	},			/* on-board controller */
+	{
+		"Adaptec BIOS: ASW-B626", 0x0f, 22
+	},			/* on-board controller */
+	{
+		"Adaptec ASW-B626 S2", 0x2e6c, 19
+	},			/* on-board controller */
+	{
+		"Adaptec BIOS:AIC-6360", 0xc, 21
+	},			/* on-board controller */
+	{
+		"ScsiPro SP-360 BIOS", 0x2873, 19
+	},			/* ScsiPro-Controller  */
+	{
+		"GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26
+	},			/* Gigabyte Local-Bus-SCSI */
+	{
+		"Adaptec BIOS:AVA-282X", 0xc, 21
+	},			/* Adaptec 282x */
+	{
+		"Adaptec IBM Dock II SCSI", 0x2edd, 24
+	},			/* IBM Thinkpad Dock II */
+	{
+		"Adaptec BIOS:AHA-1532P", 0x1c, 22
+	},			/* IBM Thinkpad Dock II SCSI */
+	{
+		"DTC3520A Host Adapter BIOS", 0x318a, 26
+	},			/* DTC 3520A ISA SCSI */
 };
+
 #define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature))
 #endif
 
 
-static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */
-{
-   unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
+static void do_pause(unsigned amount)
+{				/* Pause for amount*10 milliseconds */
+	unsigned long the_time = jiffies + amount;	/* 0.01 seconds per jiffy */
 
-   while (time_before(jiffies, the_time))
-     barrier();
+	while (time_before(jiffies, the_time))
+		barrier();
 }
 
 /*
  *  queue services:
  */
-static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC)
 {
-  Scsi_Cmnd *end;
+	Scsi_Cmnd *end;
 
-  new_SC->host_scribble = (unsigned char *) NULL;
-  if(!*SC)
-    *SC=new_SC;
-  else {
-    for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble)
-      ;
-    end->host_scribble = (unsigned char *) new_SC;
-  }
+	new_SC->host_scribble = (unsigned char *) NULL;
+	if (!*SC)
+		*SC = new_SC;
+	else {
+		for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble);
+		end->host_scribble = (unsigned char *) new_SC;
+	}
 }
 
-static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC)
 {
-  Scsi_Cmnd *ptr;
+	Scsi_Cmnd *ptr;
 
-  ptr=*SC;
-  if(ptr)
-    *SC= (Scsi_Cmnd *) (*SC)->host_scribble;
-  return ptr;
+	ptr = *SC;
+	if (ptr)
+		*SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+	return ptr;
 }
 
-static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun)
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun)
 {
-  Scsi_Cmnd *ptr, *prev;
-
-  for(ptr=*SC, prev=NULL;
-       ptr && ((ptr->target!=target) || (ptr->lun!=lun));
-      prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
-    ;
+	Scsi_Cmnd *ptr, *prev;
 
-  if(ptr){
-    if(prev)
-      prev->host_scribble = ptr->host_scribble;
-    else
-      *SC= (Scsi_Cmnd *) ptr->host_scribble;
-  }
+	for (ptr = *SC, prev = NULL;
+	     ptr && ((ptr->target != target) || (ptr->lun != lun));
+	     prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
 
-  return ptr;
+	if (ptr) {
+		if (prev)
+			prev->host_scribble = ptr->host_scribble;
+		else
+			*SC = (Scsi_Cmnd *) ptr->host_scribble;
+	}
+	return ptr;
 }
 
 /*
@@ -638,12 +666,12 @@
  */
 static void make_acklow(struct Scsi_Host *shpnt)
 {
-  SETPORT(SXFRCTL0, CH1|SPIOEN);
-  GETPORT(SCSIDAT);
-  SETPORT(SXFRCTL0, CH1);
+	SETPORT(SXFRCTL0, CH1 | SPIOEN);
+	GETPORT(SCSIDAT);
+	SETPORT(SXFRCTL0, CH1);
 
-  while(TESTHI(SCSISIG, ACKI))
-    barrier();
+	while (TESTHI(SCSISIG, ACKI))
+		barrier();
 }
 
 /*
@@ -658,61 +686,61 @@
  */
 static int getphase(struct Scsi_Host *shpnt)
 {
-  int phase, sstat1;
-  
-  while(1) {
-    do {
-      while(!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE|SCSIRSTI|REQINIT)))
-        barrier();
-      if(sstat1 & BUSFREE)
-        return P_BUSFREE;
-      if(sstat1 & SCSIRSTI) {
-        printk("aha152x: RESET IN\n");
-        SETPORT(SSTAT1, SCSIRSTI);
-      }
-    } while(TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT));
-
-    SETPORT(SSTAT1, CLRSCSIPERR);
-  
-    phase = GETPORT(SCSISIG) & P_MASK ;
-
-    if(TESTHI(SSTAT1, SCSIPERR)) {
-      if((phase & (CDO|MSGO))==0)                        /* DATA phase */
-        return P_PARITY;
-
-      make_acklow(shpnt);
-    } else
-      return phase;
-  }
+	int phase, sstat1;
+
+	while (1) {
+		do {
+			while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT)))
+				barrier();
+			if (sstat1 & BUSFREE)
+				return P_BUSFREE;
+			if (sstat1 & SCSIRSTI) {
+				printk("aha152x: RESET IN\n");
+				SETPORT(SSTAT1, SCSIRSTI);
+			}
+		} while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT));
+
+		SETPORT(SSTAT1, CLRSCSIPERR);
+
+		phase = GETPORT(SCSISIG) & P_MASK;
+
+		if (TESTHI(SSTAT1, SCSIPERR)) {
+			if ((phase & (CDO | MSGO)) == 0)	/* DATA phase */
+				return P_PARITY;
+
+			make_acklow(shpnt);
+		} else
+			return phase;
+	}
 }
 
 /* called from init/main.c */
 void aha152x_setup(char *str, int *ints)
 {
-  if(setup_count>2)
-    panic("aha152x: you can only configure up to two controllers\n");
+	if (setup_count > 2)
+		panic("aha152x: you can only configure up to two controllers\n");
 
-  setup[setup_count].conf        = str;
-  setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
-  setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
-  setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
-  setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
-  setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
-  setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */;
-  setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
-  setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
+	setup[setup_count].conf = str;
+	setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
+	setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
+	setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
+	setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
+	setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
+	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */ ;
+	setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
+	setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
 #ifdef DEBUG_AHA152X
-  setup[setup_count].debug       = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
-  if(ints[0]>9) { 
-    printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
-           "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
+	setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
+	if (ints[0] > 9) {
+		printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
 #else
-  if(ints[0]>8) {
-    printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
-           "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
+	if (ints[0] > 8) {
+		printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
 #endif
-  } else 
-    setup_count++;
+	} else
+		setup_count++;
 }
 
 /*
@@ -720,598 +748,589 @@
  */
 static int aha152x_porttest(int io_port)
 {
-  int i;
+	int i;
 
-  if(check_region(io_port, IO_RANGE))
-    return 0;
+	if (check_region(io_port, IO_RANGE))
+		return 0;
 
-  SETPORT(io_port+O_DMACNTRL1, 0);          /* reset stack pointer */
-  for(i=0; i<16; i++)
-    SETPORT(io_port+O_STACK, i);
+	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16; i++)
+		SETPORT(io_port + O_STACK, i);
 
-  SETPORT(io_port+O_DMACNTRL1, 0);          /* reset stack pointer */
-  for(i=0; i<16 && GETPORT(io_port+O_STACK)==i; i++)
-    ;
+	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++);
 
-  return(i==16);
+	return (i == 16);
 }
 
 int aha152x_checksetup(struct aha152x_setup *setup)
 {
-  int i;
-  
+	int i;
+
 #ifndef PCMCIA
-  for(i=0; i<PORT_COUNT && (setup->io_port != ports[i]); i++)
-    ;
-  
-  if(i==PORT_COUNT)
-    return 0;
-#endif
-  
-  if(!aha152x_porttest(setup->io_port))
-    return 0;
-  
-  if((setup->irq<IRQ_MIN) || (setup->irq>IRQ_MAX))
-    return 0;
-  
-  if((setup->scsiid < 0) || (setup->scsiid > 7))
-    return 0;
-  
-  if((setup->reconnect < 0) || (setup->reconnect > 1))
-    return 0;
-  
-  if((setup->parity < 0) || (setup->parity > 1))
-    return 0;
-  
-  if((setup->synchronous < 0) || (setup->synchronous > 1))
-    return 0;
-
-  if((setup->ext_trans < 0) || (setup->ext_trans > 1))
-    return 0;
-  
-  
-  return 1;
+	for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++);
+
+	if (i == PORT_COUNT)
+		return 0;
+#endif
+
+	if (!aha152x_porttest(setup->io_port))
+		return 0;
+
+	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
+		return 0;
+
+	if ((setup->scsiid < 0) || (setup->scsiid > 7))
+		return 0;
+
+	if ((setup->reconnect < 0) || (setup->reconnect > 1))
+		return 0;
+
+	if ((setup->parity < 0) || (setup->parity > 1))
+		return 0;
+
+	if ((setup->synchronous < 0) || (setup->synchronous > 1))
+		return 0;
+
+	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
+		return 0;
+
+
+	return 1;
 }
 
-void aha152x_swintr(int irqno, void *dev_id, struct pt_regs * regs)
+void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs)
 {
-  struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN];
+	struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
 
-  if(!shpnt)
-    panic("aha152x: catched software interrupt for unknown controller.\n");
+	if (!shpnt)
+		panic("aha152x: catched software interrupt for unknown controller.\n");
 
-  HOSTDATA(shpnt)->swint++;
+	HOSTDATA(shpnt)->swint++;
 }
 
 
 int aha152x_detect(Scsi_Host_Template * tpnt)
 {
-  int                 i, j, ok;
+	int i, j, ok;
 #if defined(AUTOCONF)
-  aha152x_config      conf;
+	aha152x_config conf;
 #endif
-  
-  tpnt->proc_dir = &proc_scsi_aha152x;
 
-  for(i=0; i<IRQS; i++)
-    aha152x_host[i] = (struct Scsi_Host *) NULL;
-  
-  if(setup_count) {
-    printk("aha152x: processing commandline: ");
-   
-    for(i=0; i<setup_count; i++)
-      if(!aha152x_checksetup(&setup[i])) {
-        printk("\naha152x: %s\n", setup[i].conf);
-        printk("aha152x: invalid line (controller=%d)\n", i+1);
-      }
-
-      printk("ok\n");
-  }
- 
+	tpnt->proc_dir = &proc_scsi_aha152x;
+
+	for (i = 0; i < IRQS; i++)
+		aha152x_host[i] = (struct Scsi_Host *) NULL;
+
+	if (setup_count) {
+		printk("aha152x: processing commandline: ");
+
+		for (i = 0; i < setup_count; i++)
+			if (!aha152x_checksetup(&setup[i])) {
+				printk("\naha152x: %s\n", setup[i].conf);
+				printk("aha152x: invalid line (controller=%d)\n", i + 1);
+			}
+		printk("ok\n");
+	}
 #ifdef SETUP0
-  if(setup_count<2) {
-    struct aha152x_setup override = SETUP0;
+	if (setup_count < 2) {
+		struct aha152x_setup override = SETUP0;
 
-    if(setup_count==0 || (override.io_port != setup[0].io_port))
-      if(!aha152x_checksetup(&override)) {
-        printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
-               override.io_port,
-               override.irq,
-               override.scsiid,
-               override.reconnect,
-               override.parity,
-               override.synchronous,
-               override.delay,
-               override.ext_trans);
-      } else
-        setup[setup_count++] = override;
-  }
+		if (setup_count == 0 || (override.io_port != setup[0].io_port))
+			if (!aha152x_checksetup(&override)) {
+				printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+				       override.io_port,
+				       override.irq,
+				       override.scsiid,
+				       override.reconnect,
+				       override.parity,
+				       override.synchronous,
+				       override.delay,
+				       override.ext_trans);
+			} else
+				setup[setup_count++] = override;
+	}
 #endif
 
 #ifdef SETUP1
-  if(setup_count<2) {
-    struct aha152x_setup override = SETUP1;
+	if (setup_count < 2) {
+		struct aha152x_setup override = SETUP1;
 
-    if(setup_count==0 || (override.io_port != setup[0].io_port))
-      if(!aha152x_checksetup(&override)) {
-        printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
-               override.io_port,
-               override.irq,
-               override.scsiid,
-               override.reconnect,
-               override.parity,
-               override.synchronous,
-               override.delay,
-               override.ext_trans);
-      } else
-        setup[setup_count++] = override;
-  }
+		if (setup_count == 0 || (override.io_port != setup[0].io_port))
+			if (!aha152x_checksetup(&override)) {
+				printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+				       override.io_port,
+				       override.irq,
+				       override.scsiid,
+				       override.reconnect,
+				       override.parity,
+				       override.synchronous,
+				       override.delay,
+				       override.ext_trans);
+			} else
+				setup[setup_count++] = override;
+	}
 #endif
 
 #if defined(MODULE)
-  if(setup_count<2 && aha152x[0]!=0) {
-    setup[setup_count].conf        = "";
-    setup[setup_count].io_port     = aha152x[0];
-    setup[setup_count].irq         = aha152x[1];
-    setup[setup_count].scsiid      = aha152x[2];
-    setup[setup_count].reconnect   = aha152x[3];
-    setup[setup_count].parity      = aha152x[4];
-    setup[setup_count].synchronous = aha152x[5];
-    setup[setup_count].delay       = aha152x[6];
-    setup[setup_count].ext_trans   = aha152x[7];
+	if (setup_count < 2 && aha152x[0] != 0) {
+		setup[setup_count].conf = "";
+		setup[setup_count].io_port = aha152x[0];
+		setup[setup_count].irq = aha152x[1];
+		setup[setup_count].scsiid = aha152x[2];
+		setup[setup_count].reconnect = aha152x[3];
+		setup[setup_count].parity = aha152x[4];
+		setup[setup_count].synchronous = aha152x[5];
+		setup[setup_count].delay = aha152x[6];
+		setup[setup_count].ext_trans = aha152x[7];
 #ifdef DEBUG_AHA152X
-    setup[setup_count].debug       = aha152x[8];
+		setup[setup_count].debug = aha152x[8];
 #endif
-    if(aha152x_checksetup(&setup[setup_count]))
-      setup_count++;
-    else
-      printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
-             setup[setup_count].io_port,
-             setup[setup_count].irq,
-             setup[setup_count].scsiid,
-             setup[setup_count].reconnect,
-             setup[setup_count].parity,
-             setup[setup_count].synchronous,
-             setup[setup_count].delay,
-             setup[setup_count].ext_trans);
-  }
-
-  if(setup_count<2 && aha152x1[0]!=0) {
-    setup[setup_count].conf        = "";
-    setup[setup_count].io_port     = aha152x1[0];
-    setup[setup_count].irq         = aha152x1[1];
-    setup[setup_count].scsiid      = aha152x1[2];
-    setup[setup_count].reconnect   = aha152x1[3];
-    setup[setup_count].parity      = aha152x1[4];
-    setup[setup_count].synchronous = aha152x1[5];
-    setup[setup_count].delay       = aha152x1[6];
-    setup[setup_count].ext_trans   = aha152x1[7];
+		if (aha152x_checksetup(&setup[setup_count]))
+			setup_count++;
+		else
+			printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+			       setup[setup_count].io_port,
+			       setup[setup_count].irq,
+			       setup[setup_count].scsiid,
+			       setup[setup_count].reconnect,
+			       setup[setup_count].parity,
+			       setup[setup_count].synchronous,
+			       setup[setup_count].delay,
+			       setup[setup_count].ext_trans);
+	}
+	if (setup_count < 2 && aha152x1[0] != 0) {
+		setup[setup_count].conf = "";
+		setup[setup_count].io_port = aha152x1[0];
+		setup[setup_count].irq = aha152x1[1];
+		setup[setup_count].scsiid = aha152x1[2];
+		setup[setup_count].reconnect = aha152x1[3];
+		setup[setup_count].parity = aha152x1[4];
+		setup[setup_count].synchronous = aha152x1[5];
+		setup[setup_count].delay = aha152x1[6];
+		setup[setup_count].ext_trans = aha152x1[7];
 #ifdef DEBUG_AHA152X
-    setup[setup_count].debug       = aha152x1[8];
+		setup[setup_count].debug = aha152x1[8];
 #endif
-    if(aha152x_checksetup(&setup[setup_count]))
-      setup_count++;
-    else
-      printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
-             setup[setup_count].io_port,
-             setup[setup_count].irq,
-             setup[setup_count].scsiid,
-             setup[setup_count].reconnect,
-             setup[setup_count].parity,
-             setup[setup_count].synchronous,
-             setup[setup_count].delay,
-             setup[setup_count].ext_trans);
-  }
+		if (aha152x_checksetup(&setup[setup_count]))
+			setup_count++;
+		else
+			printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+			       setup[setup_count].io_port,
+			       setup[setup_count].irq,
+			       setup[setup_count].scsiid,
+			       setup[setup_count].reconnect,
+			       setup[setup_count].parity,
+			       setup[setup_count].synchronous,
+			       setup[setup_count].delay,
+			       setup[setup_count].ext_trans);
+	}
 #endif
-  
+
 #if defined(AUTOCONF)
-  if(setup_count<2) {
+	if (setup_count < 2) {
 #if !defined(SKIP_BIOSTEST)
-    ok=0;
-    for(i=0; i < ADDRESS_COUNT && !ok; i++)
-      for(j=0; (j < SIGNATURE_COUNT) && !ok; j++)
-      	ok = check_signature(addresses[i]+signatures[j].sig_offset,
-      		signatures[j].signature, signatures[j].sig_length);
+		ok = 0;
+		for (i = 0; i < ADDRESS_COUNT && !ok; i++)
+			for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++)
+				ok = check_signature(addresses[i] + signatures[j].sig_offset,
+						     signatures[j].signature, signatures[j].sig_length);
 
-    if(!ok && setup_count==0)
-      return 0;
+		if (!ok && setup_count == 0)
+			return 0;
 
-    printk("aha152x: BIOS test: passed, ");
+		printk("aha152x: BIOS test: passed, ");
 #else
-    printk("aha152x: ");
-#endif /* !SKIP_BIOSTEST */
- 
-    ok=0;
-    for(i=0; i<PORT_COUNT && setup_count<2; i++) {
-      if((setup_count==1) && (setup[0].io_port == ports[i]))
-        continue;
-
-      if(aha152x_porttest(ports[i])) {
-        ok++;
-        setup[setup_count].io_port = ports[i];
-              
-        conf.cf_port =
-          (GETPORT(ports[i]+O_PORTA)<<8) + GETPORT(ports[i]+O_PORTB);
-              
-        setup[setup_count].irq         = IRQ_MIN + conf.cf_irq;
-        setup[setup_count].scsiid      = conf.cf_id;
-        setup[setup_count].reconnect   = conf.cf_tardisc;
-        setup[setup_count].parity      = !conf.cf_parity;
-        setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */;
-        setup[setup_count].delay       = DELAY_DEFAULT;
-        setup[setup_count].ext_trans   = 0;
+		printk("aha152x: ");
+#endif				/* !SKIP_BIOSTEST */
+
+		ok = 0;
+		for (i = 0; i < PORT_COUNT && setup_count < 2; i++) {
+			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
+				continue;
+
+			if (aha152x_porttest(ports[i])) {
+				ok++;
+				setup[setup_count].io_port = ports[i];
+
+				conf.cf_port =
+				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
+
+				setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
+				setup[setup_count].scsiid = conf.cf_id;
+				setup[setup_count].reconnect = conf.cf_tardisc;
+				setup[setup_count].parity = !conf.cf_parity;
+				setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */ ;
+				setup[setup_count].delay = DELAY_DEFAULT;
+				setup[setup_count].ext_trans = 0;
 #ifdef DEBUG_AHA152X
-        setup[setup_count].debug       = DEBUG_DEFAULT;
+				setup[setup_count].debug = DEBUG_DEFAULT;
 #endif
-        setup_count++;
-      }
-    }
+				setup_count++;
+			}
+		}
 
-    if(ok)
-      printk("auto configuration: ok, ");
-  }
+		if (ok)
+			printk("auto configuration: ok, ");
+	}
 #endif
 
-  printk("detected %d controller(s)\n", setup_count);
+	printk("detected %d controller(s)\n", setup_count);
 
-  for(i=0; i<setup_count; i++) {
-    struct Scsi_Host        *shpnt;
-    unsigned long int       the_time;
+	for (i = 0; i < setup_count; i++) {
+		struct Scsi_Host *shpnt;
+		unsigned long int the_time;
+
+		shpnt = aha152x_host[setup[i].irq - IRQ_MIN] =
+		    scsi_register(tpnt, sizeof(struct aha152x_hostdata));
+		registered_count++;
+
+		shpnt->io_port = setup[i].io_port;
+		shpnt->n_io_port = IO_RANGE;
+		shpnt->irq = setup[i].irq;
+
+		ISSUE_SC = (Scsi_Cmnd *) NULL;
+		CURRENT_SC = (Scsi_Cmnd *) NULL;
+		DISCONNECTED_SC = (Scsi_Cmnd *) NULL;
+
+		HOSTDATA(shpnt)->reconnect = setup[i].reconnect;
+		HOSTDATA(shpnt)->parity = setup[i].parity;
+		HOSTDATA(shpnt)->synchronous = setup[i].synchronous;
+		HOSTDATA(shpnt)->delay = setup[i].delay;
+		HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans;
+#ifdef DEBUG_AHA152X
+		HOSTDATA(shpnt)->debug = setup[i].debug;
+#endif
 
-    shpnt = aha152x_host[setup[i].irq-IRQ_MIN] =
-      scsi_register(tpnt, sizeof(struct aha152x_hostdata));
-    registered_count++;
+		HOSTDATA(shpnt)->aborting = 0;
+		HOSTDATA(shpnt)->abortion_complete = 0;
+		HOSTDATA(shpnt)->abort_result = 0;
+		HOSTDATA(shpnt)->commands = 0;
+
+		HOSTDATA(shpnt)->message_len = 0;
+
+		for (j = 0; j < 8; j++)
+			HOSTDATA(shpnt)->syncrate[j] = 0;
+
+		SETPORT(SCSIID, setup[i].scsiid << 4);
+		shpnt->this_id = setup[i].scsiid;
+
+		if (setup[i].reconnect)
+			shpnt->can_queue = AHA152X_MAXQUEUE;
+
+		/* RESET OUT */
+		SETBITS(SCSISEQ, SCSIRSTO);
+		do_pause(30);
+		CLRBITS(SCSISEQ, SCSIRSTO);
+		do_pause(setup[i].delay);
+
+		aha152x_reset_ports(shpnt);
+
+		printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d,"
+		       " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n",
+		       i,
+		       shpnt->io_port,
+		       shpnt->irq,
+		       shpnt->this_id,
+		     HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled",
+		       HOSTDATA(shpnt)->parity ? "enabled" : "disabled",
+		   HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled",
+		       HOSTDATA(shpnt)->delay,
+		    HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled");
+
+		request_region(shpnt->io_port, IO_RANGE, "aha152x");	/* Register */
+
+		/* not expecting any interrupts */
+		SETPORT(SIMODE0, 0);
+		SETPORT(SIMODE1, 0);
+
+		SETBITS(DMACNTRL0, INTEN);
+
+		ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt);
+		if (ok < 0) {
+			if (ok == -EINVAL)
+				printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq);
+			else if (ok == -EBUSY)
+				printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq);
+			else
+				printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq);
+			printk("aha152x: driver needs an IRQ.\n");
+
+			scsi_unregister(shpnt);
+			registered_count--;
+			release_region(shpnt->io_port, IO_RANGE);
+			shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			continue;
+		}
+		HOSTDATA(shpnt)->swint = 0;
 
-    shpnt->io_port                     = setup[i].io_port;
-    shpnt->n_io_port                   = IO_RANGE;
-    shpnt->irq                         = setup[i].irq;
+		printk("aha152x: trying software interrupt, ");
+		SETBITS(DMACNTRL0, SWINT);
 
-    ISSUE_SC                           = (Scsi_Cmnd *) NULL;
-    CURRENT_SC                         = (Scsi_Cmnd *) NULL;
-    DISCONNECTED_SC                    = (Scsi_Cmnd *) NULL;
+		the_time = jiffies + 100;
+		while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time))
+			barrier();
+
+		free_irq(shpnt->irq, shpnt);
+
+		if (!HOSTDATA(shpnt)->swint) {
+			if (TESTHI(DMASTAT, INTSTAT)) {
+				printk("lost.\n");
+			} else {
+				printk("failed.\n");
+			}
+
+			printk("aha152x: IRQ %d possibly wrong.  Please verify.\n", shpnt->irq);
+
+			scsi_unregister(shpnt);
+			registered_count--;
+			release_region(shpnt->io_port, IO_RANGE);
+			shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			continue;
+		}
+		printk("ok.\n");
 
-    HOSTDATA(shpnt)->reconnect         = setup[i].reconnect;
-    HOSTDATA(shpnt)->parity            = setup[i].parity;
-    HOSTDATA(shpnt)->synchronous       = setup[i].synchronous;
-    HOSTDATA(shpnt)->delay             = setup[i].delay;
-    HOSTDATA(shpnt)->ext_trans         = setup[i].ext_trans;
-#ifdef DEBUG_AHA152X
-    HOSTDATA(shpnt)->debug             = setup[i].debug;
-#endif
+		CLRBITS(DMACNTRL0, SWINT);
 
-    HOSTDATA(shpnt)->aborting          = 0;
-    HOSTDATA(shpnt)->abortion_complete = 0;
-    HOSTDATA(shpnt)->abort_result      = 0;
-    HOSTDATA(shpnt)->commands          = 0;
-
-    HOSTDATA(shpnt)->message_len       = 0;
-
-    for(j=0; j<8; j++)
-      HOSTDATA(shpnt)->syncrate[j] = 0;
- 
-    SETPORT(SCSIID, setup[i].scsiid << 4);
-    shpnt->this_id=setup[i].scsiid;
-  
-    if(setup[i].reconnect)
-      shpnt->can_queue=AHA152X_MAXQUEUE;
-
-    /* RESET OUT */
-    SETBITS(SCSISEQ, SCSIRSTO);
-    do_pause(30);
-    CLRBITS(SCSISEQ, SCSIRSTO);
-    do_pause(setup[i].delay);
-
-    aha152x_reset_ports(shpnt);
-      
-    printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d,"
-           " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n",
-           i,
-           shpnt->io_port,
-           shpnt->irq,
-           shpnt->this_id,
-           HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled",
-           HOSTDATA(shpnt)->parity ? "enabled" : "disabled",
-           HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled",
-           HOSTDATA(shpnt)->delay,
-           HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled");
-
-    request_region(shpnt->io_port, IO_RANGE, "aha152x");  /* Register */
-  
-    /* not expecting any interrupts */
-    SETPORT(SIMODE0, 0);
-    SETPORT(SIMODE1, 0);
-
-    SETBITS(DMACNTRL0, INTEN);
-
-    ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt);
-    if(ok<0) {
-      if(ok == -EINVAL)
-        printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq);
-      else if(ok == -EBUSY)
-        printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq);
-      else
-        printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n",                 i, ok, shpnt->irq);
-      printk("aha152x: driver needs an IRQ.\n");
-
-      scsi_unregister(shpnt);
-      registered_count--;
-      release_region(shpnt->io_port, IO_RANGE);
-      shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0;
-      continue;
-    }
-
-    HOSTDATA(shpnt)->swint=0;
-
-    printk("aha152x: trying software interrupt, ");
-    SETBITS(DMACNTRL0, SWINT);
-
-    the_time=jiffies+100;
-    while(!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time))
-      barrier();
-
-    free_irq(shpnt->irq,shpnt);
-
-    if(!HOSTDATA(shpnt)->swint) {
-      if(TESTHI(DMASTAT, INTSTAT)) {
-        printk("lost.\n");
-      } else {
-        printk("failed.\n");
-      }
-
-      printk("aha152x: IRQ %d possibly wrong.  Please verify.\n", shpnt->irq);
-
-      scsi_unregister(shpnt);
-      registered_count--;
-      release_region(shpnt->io_port, IO_RANGE);
-      shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0;
-      continue;
-    }
-
-    printk("ok.\n");
-
-    CLRBITS(DMACNTRL0, SWINT);
-
-    /* clear interrupts */
-    SETPORT(SSTAT0, 0x7f);
-    SETPORT(SSTAT1, 0xef);
-
-    if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",shpnt)<0) {
-      printk("aha152x: failed to reassign interrupt.\n");
-    }
-  }
-  
-  return (registered_count>0);
+		/* clear interrupts */
+		SETPORT(SSTAT0, 0x7f);
+		SETPORT(SSTAT1, 0xef);
+
+		if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
+			printk("aha152x: failed to reassign interrupt.\n");
+		}
+	}
+
+	return (registered_count > 0);
 }
 
 
 int aha152x_release(struct Scsi_Host *shpnt)
 {
-  if (shpnt->irq)
-    free_irq(shpnt->irq, shpnt);
-  if (shpnt->io_port)
-    release_region(shpnt->io_port, IO_RANGE);
+	if (shpnt->irq)
+		free_irq(shpnt->irq, shpnt);
+	if (shpnt->io_port)
+		release_region(shpnt->io_port, IO_RANGE);
 
-  return 0;
+	return 0;
 }
 
 /* 
  *  Queue a command and setup interrupts for a free bus.
  */
-int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
-  struct Scsi_Host *shpnt = SCpnt->host;
-  unsigned long flags;
+	struct Scsi_Host *shpnt = SCpnt->host;
+	unsigned long flags;
 
 #if defined(DEBUG_RACE)
-  enter_driver("queue");
+	enter_driver("queue");
 #else
 #if defined(DEBUG_QUEUE)
-  if(HOSTDATA(shpnt)->debug & debug_queue)
-    printk("aha152x: queue(), ");
+	if (HOSTDATA(shpnt)->debug & debug_queue)
+		printk("aha152x: queue(), ");
 #endif
 #endif
 
 #if defined(DEBUG_QUEUE)
-  if(HOSTDATA(shpnt)->debug & debug_queue) {
-    printk("SCpnt (target = %d lun = %d cmnd = ",
-           SCpnt->target, SCpnt->lun);
-    print_command(SCpnt->cmnd);
-    printk(", cmd_len=%d, pieces = %d size = %u), ",
-           SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
-    disp_ports(shpnt);
-  }
-#endif
-
-  SCpnt->scsi_done =       done;
-
-  /* setup scratch area
-     SCp.ptr              : buffer pointer
-     SCp.this_residual    : buffer length
-     SCp.buffer           : next buffer
-     SCp.buffers_residual : left buffers in list
-     SCp.phase            : current state of the command */
-  SCpnt->SCp.phase = not_issued;
-  if (SCpnt->use_sg) {
-    SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
-    SCpnt->SCp.ptr              = SCpnt->SCp.buffer->address;
-    SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-    SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-  } else {
-    SCpnt->SCp.ptr              = (char *)SCpnt->request_buffer;
-    SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
-    SCpnt->SCp.buffer           = NULL;
-    SCpnt->SCp.buffers_residual = 0;
-  }
-          
-  SCpnt->SCp.Status              = CHECK_CONDITION;
-  SCpnt->SCp.Message             = 0;
-  SCpnt->SCp.have_data_in        = 0;
-  SCpnt->SCp.sent_command        = 0;
-
-  /* Turn led on, when this is the first command. */
-  save_flags(flags);
-  cli();
-  HOSTDATA(shpnt)->commands++;
-  if(HOSTDATA(shpnt)->commands==1)
-    SETPORT(PORTA, 1);
+	if (HOSTDATA(shpnt)->debug & debug_queue) {
+		printk("SCpnt (target = %d lun = %d cmnd = ",
+		       SCpnt->target, SCpnt->lun);
+		print_command(SCpnt->cmnd);
+		printk(", cmd_len=%d, pieces = %d size = %u), ",
+		  SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+		disp_ports(shpnt);
+	}
+#endif
+
+	SCpnt->scsi_done = done;
+
+	/* setup scratch area
+	   SCp.ptr              : buffer pointer
+	   SCp.this_residual    : buffer length
+	   SCp.buffer           : next buffer
+	   SCp.buffers_residual : left buffers in list
+	   SCp.phase            : current state of the command */
+	SCpnt->SCp.phase = not_issued;
+	if (SCpnt->use_sg) {
+		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
+		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+	} else {
+		SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
+		SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer = NULL;
+		SCpnt->SCp.buffers_residual = 0;
+	}
+
+	SCpnt->SCp.Status = CHECK_CONDITION;
+	SCpnt->SCp.Message = 0;
+	SCpnt->SCp.have_data_in = 0;
+	SCpnt->SCp.sent_command = 0;
+
+	/* Turn led on, when this is the first command. */
+	save_flags(flags);
+	cli();
+	HOSTDATA(shpnt)->commands++;
+	if (HOSTDATA(shpnt)->commands == 1)
+		SETPORT(PORTA, 1);
 
 #if defined(DEBUG_QUEUES)
-  if(HOSTDATA(shpnt)->debug & debug_queues)
-    printk("i+ (%d), ", HOSTDATA(shpnt)->commands);
+	if (HOSTDATA(shpnt)->debug & debug_queues)
+		printk("i+ (%d), ", HOSTDATA(shpnt)->commands);
 #endif
-  append_SC(&ISSUE_SC, SCpnt);
-  
-  /* Enable bus free interrupt, when we aren't currently on the bus */
-  if(!CURRENT_SC) {
-    SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-    SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-  }
-  restore_flags(flags);
+	append_SC(&ISSUE_SC, SCpnt);
+
+	/* Enable bus free interrupt, when we aren't currently on the bus */
+	if (!CURRENT_SC) {
+		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+	}
+	restore_flags(flags);
 
 #if defined(DEBUG_RACE)
-  leave_driver("queue");
+	leave_driver("queue");
 #endif
 
-  return 0;
+	return 0;
 }
 
 /*
  *  We only support commands in interrupt-driven fashion
  */
-int aha152x_command(Scsi_Cmnd *SCpnt)
+int aha152x_command(Scsi_Cmnd * SCpnt)
 {
-  printk("aha152x: interrupt driven driver; use aha152x_queue()\n");
-  return -1;
+	printk("aha152x: interrupt driven driver; use aha152x_queue()\n");
+	return -1;
 }
 
 /*
  *  Abort a queued command
  *  (commands that are on the bus can't be aborted easily)
  */
-int aha152x_abort(Scsi_Cmnd *SCpnt)
+int aha152x_abort(Scsi_Cmnd * SCpnt)
 {
-  struct Scsi_Host *shpnt = SCpnt->host;
-  unsigned long flags;
-  Scsi_Cmnd *ptr, *prev;
+	struct Scsi_Host *shpnt = SCpnt->host;
+	unsigned long flags;
+	Scsi_Cmnd *ptr, *prev;
 
-  save_flags(flags);
-  cli();
+	save_flags(flags);
+	cli();
 
 #if defined(DEBUG_ABORT)
-  if(HOSTDATA(shpnt)->debug & debug_abort) { 
-    printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt);
-    show_queues(shpnt);
-  }
-#endif
-
-  /* look for command in issue queue */
-  for(ptr=ISSUE_SC, prev=NULL;
-       ptr && ptr!=SCpnt;
-       prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
-    ;
-
-  if(ptr) {
-    /* dequeue */
-    if(prev)
-      prev->host_scribble = ptr->host_scribble;
-    else
-      ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
-    HOSTDATA(shpnt)->commands--; 
-
-    restore_flags(flags);
-
-    ptr->host_scribble = NULL;
-    ptr->result = DID_ABORT << 16;
-    ptr->scsi_done(ptr);
-
-    return SCSI_ABORT_SUCCESS;
-  }
-
-  /* if the bus is busy or a command is currently processed,
-     we can't do anything more */
-  if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt)) {
-    /* fail abortion, if bus is busy */
-
-    if(!CURRENT_SC)
-      printk("bus busy w/o current command, ");
- 
-    restore_flags(flags);
-
-    return SCSI_ABORT_BUSY;
-  }
-
-  /* bus is free */
-
-  if(CURRENT_SC) { 
-    HOSTDATA(shpnt)->commands--; 
-
-    /* target entered bus free before COMMAND COMPLETE, nothing to abort */
-    restore_flags(flags);
-    CURRENT_SC->result = DID_ERROR << 16;
-    CURRENT_SC->scsi_done(CURRENT_SC);
-    CURRENT_SC = (Scsi_Cmnd *) NULL;
-
-    return SCSI_ABORT_SUCCESS;
-  }
-
-  /* look for command in disconnected queue */
-  for(ptr=DISCONNECTED_SC, prev=NULL;
-       ptr && ptr!=SCpnt;
-       prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
-    ;
-
-  if(!ptr) {
-    /* command wasn't found */
-    printk("command not found\n");
-    restore_flags(flags);
-
-    return SCSI_ABORT_NOT_RUNNING;
-  }
-
-  if(!HOSTDATA(shpnt)->aborting) {
-    /* dequeue */
-    if(prev)
-      prev->host_scribble = ptr->host_scribble;
-    else
-      DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
-    HOSTDATA(shpnt)->commands--; 
-
-    /* set command current and initiate selection,
-       let the interrupt routine take care of the abortion */
-    CURRENT_SC     = ptr;
-    ptr->SCp.phase = in_selection|aborted;
-    SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
-      
-    ADDMSG(ABORT);
-
-    /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-    SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
-    SETPORT(SIMODE1, ENSELTIMO);
-
-    /* Enable SELECTION OUT sequence */
-    SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
-
-    SETBITS(DMACNTRL0, INTEN);
-    HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS;
-    HOSTDATA(shpnt)->aborting++;
-    HOSTDATA(shpnt)->abortion_complete=0;
-
-    restore_flags(flags);
-
-    /* sleep until the abortion is complete */
-    while(!HOSTDATA(shpnt)->abortion_complete)
-      barrier();
-    HOSTDATA(shpnt)->aborting=0;
-
-    return HOSTDATA(shpnt)->abort_result;
-  } else {
-    /* we're already aborting a command */
-    restore_flags(flags);
+	if (HOSTDATA(shpnt)->debug & debug_abort) {
+		printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	/* look for command in issue queue */
+	for (ptr = ISSUE_SC, prev = NULL;
+	     ptr && ptr != SCpnt;
+	     prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+
+	if (ptr) {
+		/* dequeue */
+		if (prev)
+			prev->host_scribble = ptr->host_scribble;
+		else
+			ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble;
+
+		HOSTDATA(shpnt)->commands--;
+
+		restore_flags(flags);
+
+		ptr->host_scribble = NULL;
+		ptr->result = DID_ABORT << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		ptr->scsi_done(ptr);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+
+		return SCSI_ABORT_SUCCESS;
+	}
+	/* if the bus is busy or a command is currently processed,
+	   we can't do anything more */
+	if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) {
+		/* fail abortion, if bus is busy */
+
+		if (!CURRENT_SC)
+			printk("bus busy w/o current command, ");
+
+		restore_flags(flags);
+
+		return SCSI_ABORT_BUSY;
+	}
+	/* bus is free */
+
+	if (CURRENT_SC) {
+		HOSTDATA(shpnt)->commands--;
+
+		/* target entered bus free before COMMAND COMPLETE, nothing to abort */
+		restore_flags(flags);
+		spin_lock_irqsave(&io_request_lock, flags);
+		CURRENT_SC->result = DID_ERROR << 16;
+		CURRENT_SC->scsi_done(CURRENT_SC);
+		CURRENT_SC = (Scsi_Cmnd *) NULL;
+		spin_unlock_irqrestore(&io_request_lock, flags);
+
+		return SCSI_ABORT_SUCCESS;
+	}
+	/* look for command in disconnected queue */
+	for (ptr = DISCONNECTED_SC, prev = NULL;
+	     ptr && ptr != SCpnt;
+	     prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+
+	if (!ptr) {
+		/* command wasn't found */
+		printk("command not found\n");
+		restore_flags(flags);
+
+		return SCSI_ABORT_NOT_RUNNING;
+	}
+	if (!HOSTDATA(shpnt)->aborting) {
+		/* dequeue */
+		if (prev)
+			prev->host_scribble = ptr->host_scribble;
+		else
+			DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
+
+		HOSTDATA(shpnt)->commands--;
+
+		/* set command current and initiate selection,
+		   let the interrupt routine take care of the abortion */
+		CURRENT_SC = ptr;
+		ptr->SCp.phase = in_selection | aborted;
+		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+
+		ADDMSG(ABORT);
+
+		/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+		SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+		SETPORT(SIMODE1, ENSELTIMO);
+
+		/* Enable SELECTION OUT sequence */
+		SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+
+		SETBITS(DMACNTRL0, INTEN);
+		HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
+		HOSTDATA(shpnt)->aborting++;
+		HOSTDATA(shpnt)->abortion_complete = 0;
+
+		restore_flags(flags);
+
+		/* sleep until the abortion is complete */
+		while (!HOSTDATA(shpnt)->abortion_complete)
+			barrier();
+		HOSTDATA(shpnt)->aborting = 0;
+
+		return HOSTDATA(shpnt)->abort_result;
+	} else {
+		/* we're already aborting a command */
+		restore_flags(flags);
 
-    return SCSI_ABORT_BUSY;
-  }
+		return SCSI_ABORT_BUSY;
+	}
 }
 
 /*
@@ -1319,110 +1338,113 @@
  */
 static void aha152x_reset_ports(struct Scsi_Host *shpnt)
 {
-  /* disable interrupts */
-  SETPORT(DMACNTRL0, RSTFIFO);
+	/* disable interrupts */
+	SETPORT(DMACNTRL0, RSTFIFO);
 
-  SETPORT(SCSISEQ, 0);
+	SETPORT(SCSISEQ, 0);
 
-  SETPORT(SXFRCTL1, 0);
-  SETPORT(SCSISIG, 0);
-  SETPORT(SCSIRATE, 0);
+	SETPORT(SXFRCTL1, 0);
+	SETPORT(SCSISIG, 0);
+	SETPORT(SCSIRATE, 0);
 
-  /* clear all interrupt conditions */
-  SETPORT(SSTAT0, 0x7f);
-  SETPORT(SSTAT1, 0xef);
+	/* clear all interrupt conditions */
+	SETPORT(SSTAT0, 0x7f);
+	SETPORT(SSTAT1, 0xef);
 
-  SETPORT(SSTAT4, SYNCERR|FWERR|FRERR);
+	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
 
-  SETPORT(DMACNTRL0, 0);
-  SETPORT(DMACNTRL1, 0);
+	SETPORT(DMACNTRL0, 0);
+	SETPORT(DMACNTRL1, 0);
 
-  SETPORT(BRSTCNTRL, 0xf1);
+	SETPORT(BRSTCNTRL, 0xf1);
 
-  /* clear SCSI fifo and transfer count */
-  SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
-  SETPORT(SXFRCTL0, CH1);
+	/* clear SCSI fifo and transfer count */
+	SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
 
-  /* enable interrupts */
-  SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-  SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+	/* enable interrupts */
+	SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+	SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
 }
 
 /*
  *  Reset registers, reset a hanging bus and
  *  kill active and disconnected commands for target w/o soft reset
  */
-int aha152x_reset(Scsi_Cmnd *SCpnt, unsigned int unused)
+int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused)
 {
-  struct Scsi_Host *shpnt = SCpnt->host;
-  unsigned long flags;
-  Scsi_Cmnd *ptr, *prev, *next;
+	struct Scsi_Host *shpnt = SCpnt->host;
+	unsigned long flags;
+	Scsi_Cmnd *ptr, *prev, *next;
 
-  aha152x_reset_ports(shpnt);
+	aha152x_reset_ports(shpnt);
 
-  /* Reset, if bus hangs */
-  if(TESTLO(SSTAT1, BUSFREE)) {
-    CLRBITS(DMACNTRL0, INTEN);
+	/* Reset, if bus hangs */
+	if (TESTLO(SSTAT1, BUSFREE)) {
+		CLRBITS(DMACNTRL0, INTEN);
 
 #if defined(DEBUG_RESET)
-    if(HOSTDATA(shpnt)->debug & debug_reset) {
-      printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
-      show_queues(shpnt);
-    }
-#endif
-
-    ptr=CURRENT_SC;
-    if(ptr && !ptr->device->soft_reset) {
-      ptr->host_scribble = NULL;
-      ptr->result = DID_RESET << 16;
-      ptr->scsi_done(CURRENT_SC);
-      CURRENT_SC=NULL;
-    }
-
-    save_flags(flags);
-    cli();
-    prev=NULL; ptr=DISCONNECTED_SC;
-    while(ptr) {
-      if(!ptr->device->soft_reset) {
-        if(prev)
-          prev->host_scribble = ptr->host_scribble;
-        else
-          DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
-        next = (Scsi_Cmnd *) ptr->host_scribble;
-
-        ptr->host_scribble = NULL;
-        ptr->result        = DID_RESET << 16;
-        ptr->scsi_done(ptr);
-  
-        ptr = next; 
-      } else {
-        prev=ptr;
-        ptr = (Scsi_Cmnd *) ptr->host_scribble;
-      }
-    }
-    restore_flags(flags);
+		if (HOSTDATA(shpnt)->debug & debug_reset) {
+			printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
+			show_queues(shpnt);
+		}
+#endif
+
+		ptr = CURRENT_SC;
+		if (ptr && !ptr->device->soft_reset) {
+			ptr->host_scribble = NULL;
+			ptr->result = DID_RESET << 16;
+			spin_lock_irqsave(&io_request_lock, flags);
+			ptr->scsi_done(CURRENT_SC);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			CURRENT_SC = NULL;
+		}
+		save_flags(flags);
+		cli();
+		prev = NULL;
+		ptr = DISCONNECTED_SC;
+		while (ptr) {
+			if (!ptr->device->soft_reset) {
+				if (prev)
+					prev->host_scribble = ptr->host_scribble;
+				else
+					DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
+
+				next = (Scsi_Cmnd *) ptr->host_scribble;
+
+				ptr->host_scribble = NULL;
+				ptr->result = DID_RESET << 16;
+				spin_lock_irqsave(&io_request_lock, flags);
+				ptr->scsi_done(ptr);
+				spin_unlock_irqrestore(&io_request_lock, flags);
+
+				ptr = next;
+			} else {
+				prev = ptr;
+				ptr = (Scsi_Cmnd *) ptr->host_scribble;
+			}
+		}
+		restore_flags(flags);
 
 #if defined(DEBUG_RESET)
-    if(HOSTDATA(shpnt)->debug & debug_reset) {
-      printk("commands on targets w/ soft-resets:\n");
-      show_queues(shpnt);
-    }
+		if (HOSTDATA(shpnt)->debug & debug_reset) {
+			printk("commands on targets w/ soft-resets:\n");
+			show_queues(shpnt);
+		}
 #endif
 
-    /* RESET OUT */
-    SETPORT(SCSISEQ, SCSIRSTO);
-    do_pause(30);
-    SETPORT(SCSISEQ, 0);
-    do_pause(DELAY);
-
-    SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-    SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+		/* RESET OUT */
+		SETPORT(SCSISEQ, SCSIRSTO);
+		do_pause(30);
+		SETPORT(SCSISEQ, 0);
+		do_pause(DELAY);
 
-    SETPORT(DMACNTRL0, INTEN);
-  }
+		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
 
-  return SCSI_RESET_SUCCESS;
+		SETPORT(DMACNTRL0, INTEN);
+	}
+	return SCSI_RESET_SUCCESS;
 }
 
 /*
@@ -1430,59 +1452,58 @@
  */
 int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
 {
-  struct Scsi_Host *shpnt=disk->device->host;
+	struct Scsi_Host *shpnt = disk->device->host;
 
 #if defined(DEBUG_BIOSPARAM)
-  if(HOSTDATA(shpnt)->debug & debug_biosparam)
-    printk("aha152x_biosparam: dev=%s, size=%d, ",
-           kdevname(dev), disk->capacity);
-#endif
- 
-  /* try default translation */
-  info_array[0]=64;
-  info_array[1]=32;
-  info_array[2]=disk->capacity / (64 * 32);
-
-  /* for disks >1GB do some guessing */
-  if(info_array[2]>=1024) {
-    int info[3];
-
-    /* try to figure out the geometry from the partition table */
-    if(scsicam_bios_param(disk, dev, info)<0 ||
-       !((info[0]==64 && info[1]==32) || (info[0]==255 && info[1]==63))) {
-      if(EXT_TRANS) {
-        printk("aha152x: unable to verify geometry for disk with >1GB.\n"
-               "         using extended translation.\n");
-        info_array[0] = 255;
-        info_array[1] = 63;
-        info_array[2] = disk->capacity / (255 * 63);
-      } else {
-        printk("aha152x: unable to verify geometry for disk with >1GB.\n"
-               "         Using default translation. Please verify yourself.\n"
-               "         Perhaps you need to enable extended translation in the driver.\n"
-               "         See /usr/src/linux/drivers/scsi/aha152x.c for details.\n");
-      }
-    } else {
-      info_array[0]=info[0];
-      info_array[1]=info[1];
-      info_array[2]=info[2];
-      
-      if(info[0]==255 && !EXT_TRANS) {
-        printk("aha152x: current partition table is using extended translation.\n"
-               "         using it also, although it's not explicty enabled.\n");
-      }
-    }
-  }
-
+	if (HOSTDATA(shpnt)->debug & debug_biosparam)
+		printk("aha152x_biosparam: dev=%s, size=%d, ",
+		       kdevname(dev), disk->capacity);
+#endif
+
+	/* try default translation */
+	info_array[0] = 64;
+	info_array[1] = 32;
+	info_array[2] = disk->capacity / (64 * 32);
+
+	/* for disks >1GB do some guessing */
+	if (info_array[2] >= 1024) {
+		int info[3];
+
+		/* try to figure out the geometry from the partition table */
+		if (scsicam_bios_param(disk, dev, info) < 0 ||
+		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
+			if (EXT_TRANS) {
+				printk("aha152x: unable to verify geometry for disk with >1GB.\n"
+				"         using extended translation.\n");
+				info_array[0] = 255;
+				info_array[1] = 63;
+				info_array[2] = disk->capacity / (255 * 63);
+			} else {
+				printk("aha152x: unable to verify geometry for disk with >1GB.\n"
+				       "         Using default translation. Please verify yourself.\n"
+				       "         Perhaps you need to enable extended translation in the driver.\n"
+				       "         See /usr/src/linux/drivers/scsi/aha152x.c for details.\n");
+			}
+		} else {
+			info_array[0] = info[0];
+			info_array[1] = info[1];
+			info_array[2] = info[2];
+
+			if (info[0] == 255 && !EXT_TRANS) {
+				printk("aha152x: current partition table is using extended translation.\n"
+				       "         using it also, although it's not explicty enabled.\n");
+			}
+		}
+	}
 #if defined(DEBUG_BIOSPARAM)
-  if(HOSTDATA(shpnt)->debug & debug_biosparam) {
-    printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
-           info_array[0], info_array[1], info_array[2]);
-    printk("WARNING: check, if the bios geometry is correct.\n");
-  }
+	if (HOSTDATA(shpnt)->debug & debug_biosparam) {
+		printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+		       info_array[0], info_array[1], info_array[2]);
+		printk("WARNING: check, if the bios geometry is correct.\n");
+	}
 #endif
 
-  return 0;
+	return 0;
 }
 
 /*
@@ -1490,71 +1511,73 @@
  */
 void aha152x_done(struct Scsi_Host *shpnt, int error)
 {
-  unsigned long flags;
-  Scsi_Cmnd *done_SC;
+	unsigned long flags;
+	Scsi_Cmnd *done_SC;
 
 #if defined(DEBUG_DONE)
-  if(HOSTDATA(shpnt)->debug & debug_done) {
-    printk("\naha152x: done(), ");
-    disp_ports(shpnt);
-  }
+	if (HOSTDATA(shpnt)->debug & debug_done) {
+		printk("\naha152x: done(), ");
+		disp_ports(shpnt);
+	}
 #endif
 
-  if(CURRENT_SC) {
+	if (CURRENT_SC) {
 #if defined(DEBUG_DONE)
-    if(HOSTDATA(shpnt)->debug & debug_done)
-      printk("done(%x), ", error);
+		if (HOSTDATA(shpnt)->debug & debug_done)
+			printk("done(%x), ", error);
 #endif
 
-    save_flags(flags);
-    cli();
+		save_flags(flags);
+		cli();
 
-    done_SC = CURRENT_SC;
-    CURRENT_SC = NULL;
+		done_SC = CURRENT_SC;
+		CURRENT_SC = NULL;
 
-    /* turn led off, when no commands are in the driver */
-    HOSTDATA(shpnt)->commands--;
-    if(!HOSTDATA(shpnt)->commands)
-      SETPORT(PORTA, 0);                                  /* turn led off */
+		/* turn led off, when no commands are in the driver */
+		HOSTDATA(shpnt)->commands--;
+		if (!HOSTDATA(shpnt)->commands)
+			SETPORT(PORTA, 0);	/* turn led off */
 
 #if defined(DEBUG_QUEUES)
-    if(HOSTDATA(shpnt)->debug & debug_queues) 
-      printk("ok (%d), ", HOSTDATA(shpnt)->commands);
+		if (HOSTDATA(shpnt)->debug & debug_queues)
+			printk("ok (%d), ", HOSTDATA(shpnt)->commands);
 #endif
-    restore_flags(flags);
+		restore_flags(flags);
 
-    SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-    SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
 
 #if 0
 /* Why poll for the BUS FREE phase, when we have setup the interrupt!? */
 #if defined(DEBUG_PHASES)
-    if(HOSTDATA(shpnt)->debug & debug_phases)
-      printk("BUS FREE loop, ");
+		if (HOSTDATA(shpnt)->debug & debug_phases)
+			printk("BUS FREE loop, ");
 #endif
-    while(TESTLO(SSTAT1, BUSFREE))
-      barrier();
+		while (TESTLO(SSTAT1, BUSFREE))
+			barrier();
 #if defined(DEBUG_PHASES)
-    if(HOSTDATA(shpnt)->debug & debug_phases)
-      printk("BUS FREE\n");
+		if (HOSTDATA(shpnt)->debug & debug_phases)
+			printk("BUS FREE\n");
 #endif
 #endif
 
-    done_SC->result = error;
-    if(done_SC->scsi_done) {
+		done_SC->result = error;
+		if (done_SC->scsi_done) {
 #if defined(DEBUG_DONE)
-      if(HOSTDATA(shpnt)->debug & debug_done)
-        printk("calling scsi_done, ");
+			if (HOSTDATA(shpnt)->debug & debug_done)
+				printk("calling scsi_done, ");
 #endif
-      done_SC->scsi_done(done_SC);
+			spin_lock_irqsave(&io_request_lock, flags);
+			done_SC->scsi_done(done_SC);
+			spin_unlock_irqrestore(&io_request_lock, flags);
 #if defined(DEBUG_DONE)
-      if(HOSTDATA(shpnt)->debug & debug_done)
-        printk("done returned, ");
+			if (HOSTDATA(shpnt)->debug & debug_done)
+				printk("done returned, ");
 #endif
-    } else
-       panic("aha152x: current_SC->scsi_done() == NULL");
-  } else
-    aha152x_panic(shpnt, "done() called outside of command");
+		} else
+			panic("aha152x: current_SC->scsi_done() == NULL");
+	} else
+		aha152x_panic(shpnt, "done() called outside of command");
 }
 
 
@@ -1563,41 +1586,39 @@
 static struct tq_struct aha152x_tq;
 
 /*
- *	Run service completions on the card with interrupts enabled.
+ *    Run service completions on the card with interrupts enabled.
  */
- 
+
 static void aha152x_run(void)
 {
 	int i;
-	for(i=0;i<IRQS;i++)
-	{
-		struct Scsi_Host *shpnt=aha152x_host[i];
-		if(shpnt && HOSTDATA(shpnt)->service)
-		{
-			HOSTDATA(shpnt)->service=0;
+	for (i = 0; i < IRQS; i++) {
+		struct Scsi_Host *shpnt = aha152x_host[i];
+		if (shpnt && HOSTDATA(shpnt)->service) {
+			HOSTDATA(shpnt)->service = 0;
 			aha152x_complete(shpnt);
 		}
 	}
 }
 
 /*
- *	Interrupts handler (main routine of the driver)
+ *    Interrupts handler (main routine of the driver)
  */
 
-static void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs)
+static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN];
+	struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
 
 #if defined(DEBUG_RACE)
 	enter_driver("intr");
 #else
 #if defined(DEBUG_INTR)
-	if(HOSTDATA(shpnt)->debug & debug_intr)
+	if (HOSTDATA(shpnt)->debug & debug_intr)
 		printk("\naha152x: intr(), ");
 #endif
 #endif
 
-	if(!shpnt)
+	if (!shpnt)
 		panic("aha152x: catched interrupt for unknown controller.\n");
 
 	/* no more interrupts from the controller, while we're busy.
@@ -1606,9 +1627,9 @@
 	CLRBITS(DMACNTRL0, INTEN);
 
 	/* Poke the BH handler */
-	
-	HOSTDATA(shpnt)->service=1;
-	aha152x_tq.routine = (void *)aha152x_run;
+
+	HOSTDATA(shpnt)->service = 1;
+	aha152x_tq.routine = (void *) aha152x_run;
 	queue_task(&aha152x_tq, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 }
@@ -1616,1020 +1637,1001 @@
 static void aha152x_complete(struct Scsi_Host *shpnt)
 {
 	unsigned int flags;
-	int done=0, phase;
+	int done = 0, phase;
 
 	/* disconnected target is trying to reconnect.
 	   Only possible, if we have disconnected nexuses and
 	   nothing is occupying the bus.
 	 */
-	 
-  if(TESTHI(SSTAT0, SELDI) &&
-      DISCONNECTED_SC &&
-      (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection)) ) {
-    int identify_msg, target, i;
-
-    /* Avoid conflicts when a target reconnects
-       while we are trying to connect to another. */
-    if(CURRENT_SC) {
+
+	if (TESTHI(SSTAT0, SELDI) &&
+	    DISCONNECTED_SC &&
+	    (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) {
+		int identify_msg, target, i;
+
+		/* Avoid conflicts when a target reconnects
+		   while we are trying to connect to another. */
+		if (CURRENT_SC) {
 #if defined(DEBUG_QUEUES)
-      if(HOSTDATA(shpnt)->debug & debug_queues)
-        printk("i+, ");
+			if (HOSTDATA(shpnt)->debug & debug_queues)
+				printk("i+, ");
 #endif
-      save_flags(flags);
-      cli();
-      append_SC(&ISSUE_SC, CURRENT_SC);
-      CURRENT_SC=NULL;
-      restore_flags(flags);
-    }
-
-    /* disable sequences */
-    SETPORT(SCSISEQ, 0);
-    SETPORT(SSTAT0, CLRSELDI);
-    SETPORT(SSTAT1, CLRBUSFREE);
+			save_flags(flags);
+			cli();
+			append_SC(&ISSUE_SC, CURRENT_SC);
+			CURRENT_SC = NULL;
+			restore_flags(flags);
+		}
+		/* disable sequences */
+		SETPORT(SCSISEQ, 0);
+		SETPORT(SSTAT0, CLRSELDI);
+		SETPORT(SSTAT1, CLRBUSFREE);
 
 #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
-    if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases))
-      printk("reselected, ");
+		if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases))
+			printk("reselected, ");
 #endif
 
-    i = GETPORT(SELID) & ~(1 << shpnt->this_id);
-    target=0;
+		i = GETPORT(SELID) & ~(1 << shpnt->this_id);
+		target = 0;
 
-    if(i==0)
-      aha152x_panic(shpnt, "reconnecting target unknown");
+		if (i == 0)
+			aha152x_panic(shpnt, "reconnecting target unknown");
 
-    for(; (i & 1)==0; target++, i>>=1)
-      ;
+		for (; (i & 1) == 0; target++, i >>= 1);
 
 #if defined(DEBUG_QUEUES)
-    if(HOSTDATA(shpnt)->debug & debug_queues)
-      printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
+		if (HOSTDATA(shpnt)->debug & debug_queues)
+			printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
 #endif
-    SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
-    SETPORT(SCSISEQ, ENRESELI);
-
-    if(TESTLO(SSTAT0, SELDI))
-      aha152x_panic(shpnt, "RESELI failed");
-
-    SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f);
+		SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+		SETPORT(SCSISEQ, ENRESELI);
 
-    SETPORT(SCSISIG, P_MSGI);
+		if (TESTLO(SSTAT0, SELDI))
+			aha152x_panic(shpnt, "RESELI failed");
 
-    /* Get identify message */
-    if((i=getphase(shpnt))!=P_MSGI) {
-      printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
-      aha152x_panic(shpnt, "unknown lun");
-    }
-    SETPORT(SCSISEQ, 0);
+		SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f);
 
-    SETPORT(SXFRCTL0, CH1);
+		SETPORT(SCSISIG, P_MSGI);
 
-    identify_msg = GETPORT(SCSIBUS);
+		/* Get identify message */
+		if ((i = getphase(shpnt)) != P_MSGI) {
+			printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
+			aha152x_panic(shpnt, "unknown lun");
+		}
+		SETPORT(SCSISEQ, 0);
 
-    if(!(identify_msg & IDENTIFY_BASE)) {
-      printk("target=%d, inbound message (%02x) != IDENTIFY\n",
-             target, identify_msg);
-      aha152x_panic(shpnt, "unknown lun");
-    }
+		SETPORT(SXFRCTL0, CH1);
 
+		identify_msg = GETPORT(SCSIBUS);
 
+		if (!(identify_msg & IDENTIFY_BASE)) {
+			printk("target=%d, inbound message (%02x) != IDENTIFY\n",
+			       target, identify_msg);
+			aha152x_panic(shpnt, "unknown lun");
+		}
 #if defined(DEBUG_QUEUES)
-    if(HOSTDATA(shpnt)->debug & debug_queues)
-      printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
+		if (HOSTDATA(shpnt)->debug & debug_queues)
+			printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
 #endif
 
-    save_flags(flags);
-    cli();
+		save_flags(flags);
+		cli();
 
 #if defined(DEBUG_QUEUES)
-    if(HOSTDATA(shpnt)->debug & debug_queues)
-      printk("d-, ");
+		if (HOSTDATA(shpnt)->debug & debug_queues)
+			printk("d-, ");
 #endif
-    CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f);
+		CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f);
+
+		if (!CURRENT_SC) {
+			printk("lun=%d, ", identify_msg & 0x3f);
+			aha152x_panic(shpnt, "no disconnected command for that lun");
+		}
+		CURRENT_SC->SCp.phase &= ~disconnected;
+		restore_flags(flags);
 
-    if(!CURRENT_SC) {
-      printk("lun=%d, ", identify_msg & 0x3f);
-      aha152x_panic(shpnt, "no disconnected command for that lun");
-    }
-
-    CURRENT_SC->SCp.phase &= ~disconnected;
-    restore_flags(flags);
-
-    make_acklow(shpnt);
-    if(getphase(shpnt)!=P_MSGI) {
-      SETPORT(SIMODE0, 0);
-      SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
+		make_acklow(shpnt);
+		if (getphase(shpnt) != P_MSGI) {
+			SETPORT(SIMODE0, 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
 #if defined(DEBUG_RACE)
-      leave_driver("(reselected) intr");
+			leave_driver("(reselected) intr");
 #endif
-      SETBITS(DMACNTRL0, INTEN);
-      return;
-    }
-  }
-  
-  /* Check, if we aren't busy with a command */
-  if(!CURRENT_SC) {
-    /* bus is free to issue a queued command */
-    if(TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) {
-      save_flags(flags);
-      cli();
+			SETBITS(DMACNTRL0, INTEN);
+			return;
+		}
+	}
+	/* Check, if we aren't busy with a command */
+	if (!CURRENT_SC) {
+		/* bus is free to issue a queued command */
+		if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) {
+			save_flags(flags);
+			cli();
 #if defined(DEBUG_QUEUES)
-      if(HOSTDATA(shpnt)->debug & debug_queues)
-        printk("i-, ");
+			if (HOSTDATA(shpnt)->debug & debug_queues)
+				printk("i-, ");
 #endif
-      CURRENT_SC = remove_first_SC(&ISSUE_SC);
-      restore_flags(flags);
+			CURRENT_SC = remove_first_SC(&ISSUE_SC);
+			restore_flags(flags);
 
 #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases))
-        printk("issuing command, ");
+			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
+				printk("issuing command, ");
 #endif
-      CURRENT_SC->SCp.phase = in_selection;
+			CURRENT_SC->SCp.phase = in_selection;
 
 #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases))
-        printk("selecting %d, ", CURRENT_SC->target); 
+			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
+				printk("selecting %d, ", CURRENT_SC->target);
 #endif
-      SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+			SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
 
-      /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
-      SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
+			/* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
+			SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER);
 
-      /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-      SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
-      SETPORT(SIMODE1, ENSELTIMO);
-
-      /* Enable SELECTION OUT sequence */
-      SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
-        
-    } else {
-      /* No command we are busy with and no new to issue */
-      printk("aha152x: ignoring spurious interrupt, nothing to do\n");
-      if(TESTHI(DMACNTRL0, SWINT)) {
-        printk("aha152x: SWINT is set!  Why?\n");
-        CLRBITS(DMACNTRL0, SWINT);
-      }
-      show_queues(shpnt);
-    }
+			/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+			SETPORT(SIMODE1, ENSELTIMO);
+
+			/* Enable SELECTION OUT sequence */
+			SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+
+		} else {
+			/* No command we are busy with and no new to issue */
+			printk("aha152x: ignoring spurious interrupt, nothing to do\n");
+			if (TESTHI(DMACNTRL0, SWINT)) {
+				printk("aha152x: SWINT is set!  Why?\n");
+				CLRBITS(DMACNTRL0, SWINT);
+			}
+			show_queues(shpnt);
+		}
 
 #if defined(DEBUG_RACE)
-    leave_driver("(selecting) intr");
+		leave_driver("(selecting) intr");
 #endif
-    SETBITS(DMACNTRL0, INTEN);
-          return;
-  }
-
-  /* the bus is busy with something */
+		SETBITS(DMACNTRL0, INTEN);
+		return;
+	}
+	/* the bus is busy with something */
 
 #if defined(DEBUG_INTR)
-  if(HOSTDATA(shpnt)->debug & debug_intr)
-    disp_ports(shpnt);
+	if (HOSTDATA(shpnt)->debug & debug_intr)
+		disp_ports(shpnt);
 #endif
 
-  /* we are waiting for the result of a selection attempt */
-  if(CURRENT_SC->SCp.phase & in_selection) {
-    if(TESTLO(SSTAT1, SELTO)) {
-      /* no timeout */
-      if(TESTHI(SSTAT0, SELDO)) {
-        /* clear BUS FREE interrupt */
-        SETPORT(SSTAT1, CLRBUSFREE);
-
-        /* Disable SELECTION OUT sequence */
-        CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO);
-
-        /* Disable SELECTION OUT DONE interrupt */
-        CLRBITS(SIMODE0, ENSELDO);
-        CLRBITS(SIMODE1, ENSELTIMO);
+	/* we are waiting for the result of a selection attempt */
+	if (CURRENT_SC->SCp.phase & in_selection) {
+		if (TESTLO(SSTAT1, SELTO)) {
+			/* no timeout */
+			if (TESTHI(SSTAT0, SELDO)) {
+				/* clear BUS FREE interrupt */
+				SETPORT(SSTAT1, CLRBUSFREE);
+
+				/* Disable SELECTION OUT sequence */
+				CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+
+				/* Disable SELECTION OUT DONE interrupt */
+				CLRBITS(SIMODE0, ENSELDO);
+				CLRBITS(SIMODE1, ENSELTIMO);
 
-        if(TESTLO(SSTAT0, SELDO)) {
-          printk("aha152x: passing bus free condition\n");
+				if (TESTLO(SSTAT0, SELDO)) {
+					printk("aha152x: passing bus free condition\n");
 
 #if defined(DEBUG_RACE)
-          leave_driver("(passing bus free) intr");
+					leave_driver("(passing bus free) intr");
 #endif
-          SETBITS(DMACNTRL0, INTEN);
+					SETBITS(DMACNTRL0, INTEN);
 
-          if(CURRENT_SC->SCp.phase & aborted) {
-            HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR;
-            HOSTDATA(shpnt)->abortion_complete++;
-          }
+					if (CURRENT_SC->SCp.phase & aborted) {
+						HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
+						HOSTDATA(shpnt)->abortion_complete++;
+					}
+					aha152x_done(shpnt, DID_NO_CONNECT << 16);
 
-          aha152x_done(shpnt, DID_NO_CONNECT << 16);
-
-          return;
-        }
+					return;
+				}
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-        if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases))
-          printk("SELDO (SELID=%x), ", GETPORT(SELID));
+				if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
+					printk("SELDO (SELID=%x), ", GETPORT(SELID));
 #endif
 
-        /* selection was done */
-        SETPORT(SSTAT0, CLRSELDO);
+				/* selection was done */
+				SETPORT(SSTAT0, CLRSELDO);
 
 #if defined(DEBUG_ABORT)
-        if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted))
-          printk("(ABORT) target selected, ");
+				if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted))
+					printk("(ABORT) target selected, ");
 #endif
 
-        CURRENT_SC->SCp.phase &= ~in_selection;
-        CURRENT_SC->SCp.phase |= in_other;
-
-        ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun));
+				CURRENT_SC->SCp.phase &= ~in_selection;
+				CURRENT_SC->SCp.phase |= in_other;
 
-        if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous) {
-          ADDMSG(EXTENDED_MESSAGE);
-          ADDMSG(3);
-          ADDMSG(EXTENDED_SDTR);
-          ADDMSG(50);
-          ADDMSG(8);
+				ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun));
 
-          printk("outbound SDTR: ");
-          print_msg(&MSG(MSGLEN-5));
+				if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) {
+					ADDMSG(EXTENDED_MESSAGE);
+					ADDMSG(3);
+					ADDMSG(EXTENDED_SDTR);
+					ADDMSG(50);
+					ADDMSG(8);
 
-          SYNCRATE=0x80;
-          CURRENT_SC->SCp.phase |= in_sync;
-        }
+					printk("outbound SDTR: ");
+					print_msg(&MSG(MSGLEN - 5));
 
+					SYNCRATE = 0x80;
+					CURRENT_SC->SCp.phase |= in_sync;
+				}
 #if defined(DEBUG_RACE)
-        leave_driver("(SELDO) intr");
+				leave_driver("(SELDO) intr");
 #endif
-        SETPORT(SCSIRATE, SYNCRATE&0x7f);
+				SETPORT(SCSIRATE, SYNCRATE & 0x7f);
 
-        SETPORT(SCSISIG, P_MSGO);
+				SETPORT(SCSISIG, P_MSGO);
 
-        SETPORT(SIMODE0, 0);
-        SETPORT(SIMODE1, ENREQINIT|ENBUSFREE);
-        SETBITS(DMACNTRL0, INTEN);
+				SETPORT(SIMODE0, 0);
+				SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
+				SETBITS(DMACNTRL0, INTEN);
 
-        return;
-      } else
-        aha152x_panic(shpnt, "neither timeout nor selection\007");
-    } else {
+				return;
+			} else
+				aha152x_panic(shpnt, "neither timeout nor selection\007");
+		} else {
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases))
-        printk("SELTO, ");
+			if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
+				printk("SELTO, ");
 #endif
-      /* end selection attempt */
-      CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO);
+			/* end selection attempt */
+			CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
 
-      /* timeout */
-      SETPORT(SSTAT1, CLRSELTIMO);
+			/* timeout */
+			SETPORT(SSTAT1, CLRSELTIMO);
 
-      SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-      SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-      SETBITS(DMACNTRL0, INTEN);
+			SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+			SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+			SETBITS(DMACNTRL0, INTEN);
 #if defined(DEBUG_RACE)
-      leave_driver("(SELTO) intr");
+			leave_driver("(SELTO) intr");
 #endif
 
-      if(CURRENT_SC->SCp.phase & aborted) {
+			if (CURRENT_SC->SCp.phase & aborted) {
 #if defined(DEBUG_ABORT)
-        if(HOSTDATA(shpnt)->debug & debug_abort)
-          printk("(ABORT) selection timeout, ");
+				if (HOSTDATA(shpnt)->debug & debug_abort)
+					printk("(ABORT) selection timeout, ");
 #endif
-        HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR;
-        HOSTDATA(shpnt)->abortion_complete++;
-      }
-
-      if(TESTLO(SSTAT0, SELINGO))
-        /* ARBITRATION not won */
-        aha152x_done(shpnt, DID_BUS_BUSY << 16);
-      else
-        /* ARBITRATION won, but SELECTION failed */
-        aha152x_done(shpnt, DID_NO_CONNECT << 16);
-
-      return;
-    }
-  }
-
-  /* enable interrupt, when target leaves current phase */
-  phase = getphase(shpnt);
-  if(!(phase & ~P_MASK))                                      /* "real" phase */
-    SETPORT(SCSISIG, phase);
-  SETPORT(SSTAT1, CLRPHASECHG);
-  CURRENT_SC->SCp.phase =
-    (CURRENT_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16);
-
-  /* information transfer phase */
-  switch(phase) {
-  case P_MSGO:                                               /* MESSAGE OUT */
-    {
-      int i, identify=0, abort=0;
+				HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
+				HOSTDATA(shpnt)->abortion_complete++;
+			}
+			if (TESTLO(SSTAT0, SELINGO))
+				/* ARBITRATION not won */
+				aha152x_done(shpnt, DID_BUS_BUSY << 16);
+			else
+				/* ARBITRATION won, but SELECTION failed */
+				aha152x_done(shpnt, DID_NO_CONNECT << 16);
+
+			return;
+		}
+	}
+	/* enable interrupt, when target leaves current phase */
+	phase = getphase(shpnt);
+	if (!(phase & ~P_MASK))	/* "real" phase */
+		SETPORT(SCSISIG, phase);
+	SETPORT(SSTAT1, CLRPHASECHG);
+	CURRENT_SC->SCp.phase =
+	    (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16);
+
+	/* information transfer phase */
+	switch (phase) {
+	case P_MSGO:		/* MESSAGE OUT */
+		{
+			int i, identify = 0, abort = 0;
 
 #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases))
-        printk("MESSAGE OUT, ");
+			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases))
+				printk("MESSAGE OUT, ");
 #endif
-      if(MSGLEN==0) {
-        ADDMSG(MESSAGE_REJECT);
+			if (MSGLEN == 0) {
+				ADDMSG(MESSAGE_REJECT);
 #if defined(DEBUG_MSGO)
-        if(HOSTDATA(shpnt)->debug & debug_msgo)
-          printk("unexpected MESSAGE OUT phase; rejecting, ");
+				if (HOSTDATA(shpnt)->debug & debug_msgo)
+					printk("unexpected MESSAGE OUT phase; rejecting, ");
 #endif
-      }
-        
-      CLRBITS(SXFRCTL0, ENDMA);
-        
-      SETPORT(SIMODE0, 0);
-      SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE);
-        
-      /* wait for data latch to become ready or a phase change */
-      while(TESTLO(DMASTAT, INTSTAT))
-        barrier();
-        
+			}
+			CLRBITS(SXFRCTL0, ENDMA);
+
+			SETPORT(SIMODE0, 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+
+			/* wait for data latch to become ready or a phase change */
+			while (TESTLO(DMASTAT, INTSTAT))
+				barrier();
+
 #if defined(DEBUG_MSGO)
-      if(HOSTDATA(shpnt)->debug & debug_msgo) {
-        int i;
-            
-        printk("messages (");
-        for(i=0; i<MSGLEN; i+=print_msg(&MSG(i)), printk(" "))
-          ;
-        printk("), ");
-      }
+			if (HOSTDATA(shpnt)->debug & debug_msgo) {
+				int i;
+
+				printk("messages (");
+				for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" "));
+				printk("), ");
+			}
 #endif
-        
-      for(i=0; i<MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) {
+
+			for (i = 0; i < MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) {
 #if defined(DEBUG_MSGO)
-        if(HOSTDATA(shpnt)->debug & debug_msgo)
-          printk("%x ", MSG(i));
+				if (HOSTDATA(shpnt)->debug & debug_msgo)
+					printk("%x ", MSG(i));
 #endif
-        if(i==MSGLEN-1) {
-          /* Leave MESSAGE OUT after transfer */
-          SETPORT(SSTAT1, CLRATNO);
-        }
-          
-        SETPORT(SCSIDAT, MSG(i));
+				if (i == MSGLEN - 1) {
+					/* Leave MESSAGE OUT after transfer */
+					SETPORT(SSTAT1, CLRATNO);
+				}
+				SETPORT(SCSIDAT, MSG(i));
 
-        make_acklow(shpnt);
-        getphase(shpnt);
+				make_acklow(shpnt);
+				getphase(shpnt);
 
-        if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun))
-          identify++;
+				if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun))
+					identify++;
 
-        if(MSG(i)==ABORT)
-          abort++;
+				if (MSG(i) == ABORT)
+					abort++;
 
-      }
+			}
 
-      MSGLEN=0;
+			MSGLEN = 0;
 
-      if(identify)
-        CURRENT_SC->SCp.phase |= sent_ident;
+			if (identify)
+				CURRENT_SC->SCp.phase |= sent_ident;
 
-      if(abort) {
-        /* revive abort(); abort() enables interrupts */
-        HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS;
-        HOSTDATA(shpnt)->abortion_complete++;
+			if (abort) {
+				/* revive abort(); abort() enables interrupts */
+				HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
+				HOSTDATA(shpnt)->abortion_complete++;
 
-        CURRENT_SC->SCp.phase &= ~(P_MASK<<16);
+				CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
 
-        /* exit */
-        SETBITS(DMACNTRL0, INTEN);
+				/* exit */
+				SETBITS(DMACNTRL0, INTEN);
 #if defined(DEBUG_RACE)
-        leave_driver("(ABORT) intr");
+				leave_driver("(ABORT) intr");
 #endif
-        aha152x_done(shpnt, DID_ABORT<<16);
+				aha152x_done(shpnt, DID_ABORT << 16);
 
-        return;
-      }
-    }
-    break;
+				return;
+			}
+		}
+		break;
 
-  case P_CMD:                                          /* COMMAND phase */
+	case P_CMD:		/* COMMAND phase */
 #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
-    if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases))
-      printk("COMMAND, ");
+		if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases))
+			printk("COMMAND, ");
 #endif
-    if(!(CURRENT_SC->SCp.sent_command)) {
-      int i;
+		if (!(CURRENT_SC->SCp.sent_command)) {
+			int i;
+
+			CLRBITS(SXFRCTL0, ENDMA);
+
+			SETPORT(SIMODE0, 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+
+			/* wait for data latch to become ready or a phase change */
+			while (TESTLO(DMASTAT, INTSTAT))
+				barrier();
 
-      CLRBITS(SXFRCTL0, ENDMA);
+			for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) {
+				SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
+
+				make_acklow(shpnt);
+				getphase(shpnt);
+			}
+
+			if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
+				aha152x_panic(shpnt, "target left COMMAND");
+
+			CURRENT_SC->SCp.sent_command++;
+		} else
+			aha152x_panic(shpnt, "Nothing to send while in COMMAND");
+		break;
+
+	case P_MSGI:		/* MESSAGE IN phase */
+		{
+			int start_sync = 0;
 
-      SETPORT(SIMODE0, 0);
-      SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE);
-  
-      /* wait for data latch to become ready or a phase change */
-      while(TESTLO(DMASTAT, INTSTAT))
-        barrier();
-  
-      for(i=0; i<CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) {
-        SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
-
-        make_acklow(shpnt);
-        getphase(shpnt);
-      }
-
-      if(i<CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
-        aha152x_panic(shpnt, "target left COMMAND");
-
-      CURRENT_SC->SCp.sent_command++;
-    } else
-      aha152x_panic(shpnt, "Nothing to send while in COMMAND");
-      break;
-
-  case P_MSGI:                                          /* MESSAGE IN phase */
-    {
-      int start_sync=0;
-        
 #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases))
-        printk("MESSAGE IN, ");
+			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases))
+				printk("MESSAGE IN, ");
 #endif
-      SETPORT(SXFRCTL0, CH1);
+			SETPORT(SXFRCTL0, CH1);
+
+			SETPORT(SIMODE0, 0);
+			SETPORT(SIMODE1, ENBUSFREE);
 
-      SETPORT(SIMODE0, 0);
-      SETPORT(SIMODE1, ENBUSFREE);
-  
-      while(phase == P_MSGI) {
-        CURRENT_SC->SCp.Message = GETPORT(SCSIDAT);
-        switch(CURRENT_SC->SCp.Message) {
-        case DISCONNECT:
+			while (phase == P_MSGI) {
+				CURRENT_SC->SCp.Message = GETPORT(SCSIDAT);
+				switch (CURRENT_SC->SCp.Message) {
+				case DISCONNECT:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-          if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases))
-            printk("target disconnected, ");
+					if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
+						printk("target disconnected, ");
 #endif
-          CURRENT_SC->SCp.Message = 0;
-          CURRENT_SC->SCp.phase   |= disconnected;
-          if(!HOSTDATA(shpnt)->reconnect)
-            aha152x_panic(shpnt, "target was not allowed to disconnect");
-
-          break;
-        
-        case COMMAND_COMPLETE:
+					CURRENT_SC->SCp.Message = 0;
+					CURRENT_SC->SCp.phase |= disconnected;
+					if (!HOSTDATA(shpnt)->reconnect)
+						aha152x_panic(shpnt, "target was not allowed to disconnect");
+
+					break;
+
+				case COMMAND_COMPLETE:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-          if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases))
-            printk("inbound message (COMMAND COMPLETE), ");
+					if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
+						printk("inbound message (COMMAND COMPLETE), ");
 #endif
-          done++;
-          break;
+					done++;
+					break;
 
-        case MESSAGE_REJECT:
-          if(CURRENT_SC->SCp.phase & in_sync) { 
-            CURRENT_SC->SCp.phase &= ~in_sync;
-            SYNCRATE=0x80;
-            printk("synchronous rejected, ");
-          } else
-            printk("inbound message (MESSAGE REJECT), ");
+				case MESSAGE_REJECT:
+					if (CURRENT_SC->SCp.phase & in_sync) {
+						CURRENT_SC->SCp.phase &= ~in_sync;
+						SYNCRATE = 0x80;
+						printk("synchronous rejected, ");
+					} else
+						printk("inbound message (MESSAGE REJECT), ");
 #if defined(DEBUG_MSGI)
-          if(HOSTDATA(shpnt)->debug & debug_msgi)
-            printk("inbound message (MESSAGE REJECT), ");
+					if (HOSTDATA(shpnt)->debug & debug_msgi)
+						printk("inbound message (MESSAGE REJECT), ");
 #endif
-          break;
+					break;
 
-        case SAVE_POINTERS:
+				case SAVE_POINTERS:
 #if defined(DEBUG_MSGI)
-          if(HOSTDATA(shpnt)->debug & debug_msgi)
-            printk("inbound message (SAVE DATA POINTERS), ");
+					if (HOSTDATA(shpnt)->debug & debug_msgi)
+						printk("inbound message (SAVE DATA POINTERS), ");
 #endif
-          break;
+					break;
 
-        case RESTORE_POINTERS:
+				case RESTORE_POINTERS:
 #if defined(DEBUG_MSGI)
-          if(HOSTDATA(shpnt)->debug & debug_msgi)
-            printk("inbound message (RESTORE DATA POINTERS), ");
+					if (HOSTDATA(shpnt)->debug & debug_msgi)
+						printk("inbound message (RESTORE DATA POINTERS), ");
 #endif
-          break;
+					break;
 
-        case EXTENDED_MESSAGE:
-          { 
-            char buffer[16];
-            int  i;
+				case EXTENDED_MESSAGE:
+					{
+						char buffer[16];
+						int i;
 
 #if defined(DEBUG_MSGI)
-            if(HOSTDATA(shpnt)->debug & debug_msgi)
-              printk("inbound message (EXTENDED MESSAGE), ");
+						if (HOSTDATA(shpnt)->debug & debug_msgi)
+							printk("inbound message (EXTENDED MESSAGE), ");
 #endif
-            make_acklow(shpnt);
-            if(getphase(shpnt)!=P_MSGI)
-              break;
-  
-            buffer[0]=EXTENDED_MESSAGE;
-            buffer[1]=GETPORT(SCSIDAT);
-
-            for(i=0; i<buffer[1] &&
-                     (make_acklow(shpnt), getphase(shpnt)==P_MSGI); i++)
-              buffer[2+i]=GETPORT(SCSIDAT);
+						make_acklow(shpnt);
+						if (getphase(shpnt) != P_MSGI)
+							break;
+
+						buffer[0] = EXTENDED_MESSAGE;
+						buffer[1] = GETPORT(SCSIDAT);
+
+						for (i = 0; i < buffer[1] &&
+						     (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++)
+							buffer[2 + i] = GETPORT(SCSIDAT);
 
 #if defined(DEBUG_MSGI)
-            if(HOSTDATA(shpnt)->debug & debug_msgi)
-              print_msg(buffer);
+						if (HOSTDATA(shpnt)->debug & debug_msgi)
+							print_msg(buffer);
 #endif
 
-            switch(buffer [2]) {
-            case EXTENDED_SDTR:
-              {
-                long ticks;
-
-                if(buffer[1]!=3)
-                  aha152x_panic(shpnt, "SDTR message length != 3");
-
-                if(!HOSTDATA(shpnt)->synchronous)
-                  break;
-
-                printk("inbound SDTR: "); print_msg(buffer);
-
-                ticks=(buffer[3]*4+49)/50;
-
-                if(CURRENT_SC->SCp.phase & in_sync) {
-                  /* we initiated SDTR */
-                  if(ticks>9 || buffer[4]<1 || buffer[4]>8)
-                    aha152x_panic(shpnt, "received SDTR invalid");
-
-                  SYNCRATE |= ((ticks-2)<<4) + buffer[4];
-                } else if(ticks<=9 && buffer[4]>=1) {
-                  if(buffer[4]>8)
-                    buffer[4]=8;
-        
-                  ADDMSG(EXTENDED_MESSAGE);
-                  ADDMSG(3);
-                  ADDMSG(EXTENDED_SDTR);
-                  if(ticks<4) {
-                    ticks=4;
-                    ADDMSG(50);
-                  } else
-                    ADDMSG(buffer[3]);
-
-                  ADDMSG(buffer[4]);
-
-                  printk("outbound SDTR: ");
-                  print_msg(&MSG(MSGLEN-5));
-
-                  CURRENT_SC->SCp.phase |= in_sync;
-                   
-                  SYNCRATE |= ((ticks-2)<<4) + buffer[4];
-
-                  start_sync++;
-                } else {
-                  /* requested SDTR is too slow, do it asynchronously */
-                  ADDMSG(MESSAGE_REJECT);
-                  SYNCRATE = 0;
-                } 
-
-                SETPORT(SCSIRATE, SYNCRATE&0x7f);
-              }
-              break;
-                      
-            case EXTENDED_MODIFY_DATA_POINTER:
-            case EXTENDED_EXTENDED_IDENTIFY:
-            case EXTENDED_WDTR:
-            default:
-              ADDMSG(MESSAGE_REJECT);
-              break;
-            }
-          }
-          break;
-       
-        default:
-          printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message);
-          break;
-
-        }
-
-        make_acklow(shpnt);
-        phase=getphase(shpnt);
-      } 
-
-      if(start_sync)
-        CURRENT_SC->SCp.phase |= in_sync;
-      else
-        CURRENT_SC->SCp.phase &= ~in_sync;
-        
-      if(MSGLEN>0)
-        SETPORT(SCSISIG, P_MSGI|ATNO);
-        
-      /* clear SCSI fifo on BUSFREE */
-      if(phase==P_BUSFREE)
-        SETPORT(SXFRCTL0, CH1|CLRCH1);
-
-      if(CURRENT_SC->SCp.phase & disconnected) {
-        save_flags(flags);
-        cli();
+						switch (buffer[2]) {
+						case EXTENDED_SDTR:
+							{
+								long ticks;
+
+								if (buffer[1] != 3)
+									aha152x_panic(shpnt, "SDTR message length != 3");
+
+								if (!HOSTDATA(shpnt)->synchronous)
+									break;
+
+								printk("inbound SDTR: ");
+								print_msg(buffer);
+
+								ticks = (buffer[3] * 4 + 49) / 50;
+
+								if (CURRENT_SC->SCp.phase & in_sync) {
+									/* we initiated SDTR */
+									if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8)
+										aha152x_panic(shpnt, "received SDTR invalid");
+
+									SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
+								} else if (ticks <= 9 && buffer[4] >= 1) {
+									if (buffer[4] > 8)
+										buffer[4] = 8;
+
+									ADDMSG(EXTENDED_MESSAGE);
+									ADDMSG(3);
+									ADDMSG(EXTENDED_SDTR);
+									if (ticks < 4) {
+										ticks = 4;
+										ADDMSG(50);
+									} else
+										ADDMSG(buffer[3]);
+
+									ADDMSG(buffer[4]);
+
+									printk("outbound SDTR: ");
+									print_msg(&MSG(MSGLEN - 5));
+
+									CURRENT_SC->SCp.phase |= in_sync;
+
+									SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
+
+									start_sync++;
+								} else {
+									/* requested SDTR is too slow, do it asynchronously */
+									ADDMSG(MESSAGE_REJECT);
+									SYNCRATE = 0;
+								}
+
+								SETPORT(SCSIRATE, SYNCRATE & 0x7f);
+							}
+							break;
+
+						case EXTENDED_MODIFY_DATA_POINTER:
+						case EXTENDED_EXTENDED_IDENTIFY:
+						case EXTENDED_WDTR:
+						default:
+							ADDMSG(MESSAGE_REJECT);
+							break;
+						}
+					}
+					break;
+
+				default:
+					printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message);
+					break;
+
+				}
+
+				make_acklow(shpnt);
+				phase = getphase(shpnt);
+			}
+
+			if (start_sync)
+				CURRENT_SC->SCp.phase |= in_sync;
+			else
+				CURRENT_SC->SCp.phase &= ~in_sync;
+
+			if (MSGLEN > 0)
+				SETPORT(SCSISIG, P_MSGI | ATNO);
+
+			/* clear SCSI fifo on BUSFREE */
+			if (phase == P_BUSFREE)
+				SETPORT(SXFRCTL0, CH1 | CLRCH1);
+
+			if (CURRENT_SC->SCp.phase & disconnected) {
+				save_flags(flags);
+				cli();
 #if defined(DEBUG_QUEUES)
-        if(HOSTDATA(shpnt)->debug & debug_queues)
-          printk("d+, ");
+				if (HOSTDATA(shpnt)->debug & debug_queues)
+					printk("d+, ");
 #endif
-        append_SC(&DISCONNECTED_SC, CURRENT_SC);
-        CURRENT_SC->SCp.phase |= 1<<16;
-        CURRENT_SC = NULL;
-        restore_flags(flags);
+				append_SC(&DISCONNECTED_SC, CURRENT_SC);
+				CURRENT_SC->SCp.phase |= 1 << 16;
+				CURRENT_SC = NULL;
+				restore_flags(flags);
 
-        SETBITS(SCSISEQ, ENRESELI);
+				SETBITS(SCSISEQ, ENRESELI);
 
-        SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-        SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+				SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+				SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
 
-        SETBITS(DMACNTRL0, INTEN);
+				SETBITS(DMACNTRL0, INTEN);
 
-        return;
-      }
-    }
-    break;
+				return;
+			}
+		}
+		break;
 
-  case P_STATUS:                                         /* STATUS IN phase */
+	case P_STATUS:		/* STATUS IN phase */
 #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-    if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases))
-      printk("STATUS, ");
+		if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases))
+			printk("STATUS, ");
 #endif
-    SETPORT(SXFRCTL0, CH1);
+		SETPORT(SXFRCTL0, CH1);
 
-    SETPORT(SIMODE0, 0);
-    SETPORT(SIMODE1, ENREQINIT|ENBUSFREE);
+		SETPORT(SIMODE0, 0);
+		SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
 
-    if(TESTHI(SSTAT1, PHASEMIS))
-      printk("aha152x: passing STATUS phase");
-      
-    CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
-    make_acklow(shpnt);
-    getphase(shpnt);
+		if (TESTHI(SSTAT1, PHASEMIS))
+			printk("aha152x: passing STATUS phase");
+
+		CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
+		make_acklow(shpnt);
+		getphase(shpnt);
 
 #if defined(DEBUG_STATUS)
-    if(HOSTDATA(shpnt)->debug & debug_status) {
-      printk("inbound status ");
-      print_status(CURRENT_SC->SCp.Status);
-      printk(", ");
-    }
-#endif
-    break;
-
-  case P_DATAI:                                            /* DATA IN phase */
-    {
-      int fifodata, data_count, done;
+		if (HOSTDATA(shpnt)->debug & debug_status) {
+			printk("inbound status ");
+			print_status(CURRENT_SC->SCp.Status);
+			printk(", ");
+		}
+#endif
+		break;
+
+	case P_DATAI:		/* DATA IN phase */
+		{
+			int fifodata, data_count, done;
 
 #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases))
-        printk("DATA IN, ");
+			if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases))
+				printk("DATA IN, ");
 #endif
 
 #if 0
-      if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
-        printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
-               GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+			if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT))
+				printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
+				       GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
 #endif
 
-      /* reset host fifo */
-      SETPORT(DMACNTRL0, RSTFIFO);
-      SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
+			/* reset host fifo */
+			SETPORT(DMACNTRL0, RSTFIFO);
+			SETPORT(DMACNTRL0, RSTFIFO | ENDMA);
 
-      SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
+			SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN);
 
-      SETPORT(SIMODE0, 0);
-      SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
+			SETPORT(SIMODE0, 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
 
-      /* done is set when the FIFO is empty after the target left DATA IN */
-      done=0;
-      
-      /* while the target stays in DATA to transfer data */
-      while (!done) {
+			/* done is set when the FIFO is empty after the target left DATA IN */
+			done = 0;
+
+			/* while the target stays in DATA to transfer data */
+			while (!done) {
 #if defined(DEBUG_DATAI)
-        if(HOSTDATA(shpnt)->debug & debug_datai)
-          printk("expecting data, ");
+				if (HOSTDATA(shpnt)->debug & debug_datai)
+					printk("expecting data, ");
 #endif
-        /* wait for PHASEMIS or full FIFO */
-        while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT))
-          barrier();
+				/* wait for PHASEMIS or full FIFO */
+				while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT))
+					barrier();
 
 #if defined(DEBUG_DATAI)
-        if(HOSTDATA(shpnt)->debug & debug_datai)
-          printk("ok, ");
+				if (HOSTDATA(shpnt)->debug & debug_datai)
+					printk("ok, ");
 #endif
-           
-        if(TESTHI(DMASTAT, DFIFOFULL))
-          fifodata=GETPORT(FIFOSTAT);
-        else {
-          /* wait for SCSI fifo to get empty */
-          while(TESTLO(SSTAT2, SEMPTY))
-            barrier();
 
-          /* rest of data in FIFO */
-          fifodata=GETPORT(FIFOSTAT);
+				if (TESTHI(DMASTAT, DFIFOFULL))
+					fifodata = GETPORT(FIFOSTAT);
+				else {
+					/* wait for SCSI fifo to get empty */
+					while (TESTLO(SSTAT2, SEMPTY))
+						barrier();
+
+					/* rest of data in FIFO */
+					fifodata = GETPORT(FIFOSTAT);
 #if defined(DEBUG_DATAI)
-          if(HOSTDATA(shpnt)->debug & debug_datai)
-            printk("last transfer, ");
+					if (HOSTDATA(shpnt)->debug & debug_datai)
+						printk("last transfer, ");
 #endif
-          done=1;
-        }
-  
+					done = 1;
+				}
+
 #if defined(DEBUG_DATAI)
-        if(HOSTDATA(shpnt)->debug & debug_datai)
-          printk("fifodata=%d, ", fifodata);
+				if (HOSTDATA(shpnt)->debug & debug_datai)
+					printk("fifodata=%d, ", fifodata);
 #endif
 
-        while(fifodata && CURRENT_SC->SCp.this_residual) {
-          data_count=fifodata;
-  
-          /* limit data transfer to size of first sg buffer */
-          if(data_count > CURRENT_SC->SCp.this_residual)
-            data_count = CURRENT_SC->SCp.this_residual;
-  
-          fifodata -= data_count;
+				while (fifodata && CURRENT_SC->SCp.this_residual) {
+					data_count = fifodata;
+
+					/* limit data transfer to size of first sg buffer */
+					if (data_count > CURRENT_SC->SCp.this_residual)
+						data_count = CURRENT_SC->SCp.this_residual;
+
+					fifodata -= data_count;
 
 #if defined(DEBUG_DATAI)
-          if(HOSTDATA(shpnt)->debug & debug_datai)
-            printk("data_count=%d, ", data_count);
+					if (HOSTDATA(shpnt)->debug & debug_datai)
+						printk("data_count=%d, ", data_count);
 #endif
-  
-          if(data_count&1) {
-            /* get a single byte in byte mode */
-            SETBITS(DMACNTRL0, _8BIT);
-            *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
-            CURRENT_SC->SCp.this_residual--;
-          }
- 
-          if(data_count>1) {
-            CLRBITS(DMACNTRL0, _8BIT);
-            data_count >>= 1; /* Number of words */
-            insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+
+					if (data_count & 1) {
+						/* get a single byte in byte mode */
+						SETBITS(DMACNTRL0, _8BIT);
+						*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+						CURRENT_SC->SCp.this_residual--;
+					}
+					if (data_count > 1) {
+						CLRBITS(DMACNTRL0, _8BIT);
+						data_count >>= 1;	/* Number of words */
+						insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
 #if defined(DEBUG_DATAI)
-            if(HOSTDATA(shpnt)->debug & debug_datai)
-              /* show what comes with the last transfer */
-              if(done) {
+						if (HOSTDATA(shpnt)->debug & debug_datai)
+							/* show what comes with the last transfer */
+							if (done) {
 #if 0
-                int           i;
-                unsigned char *data;
+								int i;
+								unsigned char *data;
 #endif
-  
-                printk("data on last transfer (%d bytes) ",
-                       2*data_count);
-#if 0
-                printk("data on last transfer (%d bytes: ",
-                       2*data_count);
-                data = (unsigned char *) CURRENT_SC->SCp.ptr;
-                for(i=0; i<2*data_count; i++)
-                  printk("%2x ", *data++);
-                printk("), ");
-#endif
-              }
-#endif
-            CURRENT_SC->SCp.ptr           += 2 * data_count;
-            CURRENT_SC->SCp.this_residual -= 2 * data_count;
-          }
-             
-          /* if this buffer is full and there are more buffers left */
-          if(!CURRENT_SC->SCp.this_residual &&
-             CURRENT_SC->SCp.buffers_residual) {
-            /* advance to next buffer */
-            CURRENT_SC->SCp.buffers_residual--;
-            CURRENT_SC->SCp.buffer++;
-            CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address;
-            CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
-          } 
-        }
- 
-        /*
-         * FIFO should be empty
-         */
-        if(fifodata>0) {
-          printk("aha152x: more data than expected (%d bytes)\n",
-                 GETPORT(FIFOSTAT));
-          SETBITS(DMACNTRL0, _8BIT);
-          printk("aha152x: data (");
-          while(fifodata--)
-            printk("%2x ", GETPORT(DATAPORT));
-            printk(")\n");
-        }
 
+								printk("data on last transfer (%d bytes) ",
+								       2 * data_count);
+#if 0
+								printk("data on last transfer (%d bytes: ",
+								       2 * data_count);
+								data = (unsigned char *) CURRENT_SC->SCp.ptr;
+								for (i = 0; i < 2 * data_count; i++)
+									printk("%2x ", *data++);
+								printk("), ");
+#endif
+							}
+#endif
+						CURRENT_SC->SCp.ptr += 2 * data_count;
+						CURRENT_SC->SCp.this_residual -= 2 * data_count;
+					}
+					/* if this buffer is full and there are more buffers left */
+					if (!CURRENT_SC->SCp.this_residual &&
+					    CURRENT_SC->SCp.buffers_residual) {
+						/* advance to next buffer */
+						CURRENT_SC->SCp.buffers_residual--;
+						CURRENT_SC->SCp.buffer++;
+						CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
+						CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+					}
+				}
+
+				/*
+				 * FIFO should be empty
+				 */
+				if (fifodata > 0) {
+					printk("aha152x: more data than expected (%d bytes)\n",
+					       GETPORT(FIFOSTAT));
+					SETBITS(DMACNTRL0, _8BIT);
+					printk("aha152x: data (");
+					while (fifodata--)
+						printk("%2x ", GETPORT(DATAPORT));
+					printk(")\n");
+				}
 #if defined(DEBUG_DATAI)
-        if(HOSTDATA(shpnt)->debug & debug_datai)
-          if(!fifodata)
-            printk("fifo empty, ");
-          else
-           printk("something left in fifo, ");
+				if (HOSTDATA(shpnt)->debug & debug_datai)
+					if (!fifodata)
+						printk("fifo empty, ");
+					else
+						printk("something left in fifo, ");
 #endif
-      }
+			}
 
 #if defined(DEBUG_DATAI)
-      if((HOSTDATA(shpnt)->debug & debug_datai) &&
-         (CURRENT_SC->SCp.buffers_residual ||
-          CURRENT_SC->SCp.this_residual))
-        printk("left buffers (buffers=%d, bytes=%d), ",
-               CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual);
-#endif
-      /* transfer can be considered ended, when SCSIEN reads back zero */
-      CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
-      while(TESTHI(SXFRCTL0, SCSIEN))
-        barrier();
-      CLRBITS(DMACNTRL0, ENDMA);
+			if ((HOSTDATA(shpnt)->debug & debug_datai) &&
+			    (CURRENT_SC->SCp.buffers_residual ||
+			     CURRENT_SC->SCp.this_residual))
+				printk("left buffers (buffers=%d, bytes=%d), ",
+				       CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual);
+#endif
+			/* transfer can be considered ended, when SCSIEN reads back zero */
+			CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
+			while (TESTHI(SXFRCTL0, SCSIEN))
+				barrier();
+			CLRBITS(DMACNTRL0, ENDMA);
 
 #if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
-      if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr))
-        printk("got %d bytes, ", GETSTCNT());
+			if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr))
+				printk("got %d bytes, ", GETSTCNT());
 #endif
 
-      CURRENT_SC->SCp.have_data_in++;
-    }
-    break;
+			CURRENT_SC->SCp.have_data_in++;
+		}
+		break;
 
-  case P_DATAO:                                           /* DATA OUT phase */
-    {
-      int data_count;
+	case P_DATAO:		/* DATA OUT phase */
+		{
+			int data_count;
 
 #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-      if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases))
-        printk("DATA OUT, ");
+			if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases))
+				printk("DATA OUT, ");
 #endif
 #if defined(DEBUG_DATAO)
-      if(HOSTDATA(shpnt)->debug & debug_datao)
-        printk("got data to send (bytes=%d, buffers=%d), ",
-               CURRENT_SC->SCp.this_residual,
-               CURRENT_SC->SCp.buffers_residual);
-#endif
-
-      if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) {
-        printk("%d(%d) left in FIFO, ",
-               GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
-        aha152x_panic(shpnt, "FIFO should be empty");
-      }
-
-      SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1);
-      SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
-        
-      SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
-      SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
-
-      SETPORT(SIMODE0, 0);
-      SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
-
-      /* while current buffer is not empty or
-         there are more buffers to transfer */
-      while(TESTLO(SSTAT1, PHASEMIS) &&
-            (CURRENT_SC->SCp.this_residual ||
-            CURRENT_SC->SCp.buffers_residual)) {
+			if (HOSTDATA(shpnt)->debug & debug_datao)
+				printk("got data to send (bytes=%d, buffers=%d), ",
+				       CURRENT_SC->SCp.this_residual,
+				       CURRENT_SC->SCp.buffers_residual);
+#endif
+
+			if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) {
+				printk("%d(%d) left in FIFO, ",
+				       GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
+				aha152x_panic(shpnt, "FIFO should be empty");
+			}
+			SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1);
+			SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1);
+
+			SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+			SETPORT(DMACNTRL0, ENDMA | WRITE_READ);
+
+			SETPORT(SIMODE0, 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+
+			/* while current buffer is not empty or
+			   there are more buffers to transfer */
+			while (TESTLO(SSTAT1, PHASEMIS) &&
+			       (CURRENT_SC->SCp.this_residual ||
+				CURRENT_SC->SCp.buffers_residual)) {
 #if defined(DEBUG_DATAO)
-        if(HOSTDATA(shpnt)->debug & debug_datao)
-          printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
-                 CURRENT_SC->SCp.this_residual,
-                 CURRENT_SC->SCp.buffers_residual);
-#endif
-        /* transfer rest of buffer, but max. 128 byte */
-        data_count =
-          CURRENT_SC->SCp.this_residual > 128 ?
-          128 : CURRENT_SC->SCp.this_residual ;
+				if (HOSTDATA(shpnt)->debug & debug_datao)
+					printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
+					   CURRENT_SC->SCp.this_residual,
+					CURRENT_SC->SCp.buffers_residual);
+#endif
+				/* transfer rest of buffer, but max. 128 byte */
+				data_count =
+				    CURRENT_SC->SCp.this_residual > 128 ?
+				    128 : CURRENT_SC->SCp.this_residual;
 
 #if defined(DEBUG_DATAO)
-        if(HOSTDATA(shpnt)->debug & debug_datao)
-          printk("data_count=%d, ", data_count);
+				if (HOSTDATA(shpnt)->debug & debug_datao)
+					printk("data_count=%d, ", data_count);
 #endif
-  
-        if(data_count&1) {
-          /* put a single byte in byte mode */
-          SETBITS(DMACNTRL0, _8BIT);
-          SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
-          CURRENT_SC->SCp.this_residual--;
-        }
-        if(data_count>1) {
-          CLRBITS(DMACNTRL0, _8BIT);
-          data_count >>= 1; /* number of words */
-          outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-          CURRENT_SC->SCp.ptr           += 2 * data_count;
-          CURRENT_SC->SCp.this_residual -= 2 * data_count;
-        }
-
-        /* wait for FIFO to get empty */
-        while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT))
-          barrier();
+
+				if (data_count & 1) {
+					/* put a single byte in byte mode */
+					SETBITS(DMACNTRL0, _8BIT);
+					SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+					CURRENT_SC->SCp.this_residual--;
+				}
+				if (data_count > 1) {
+					CLRBITS(DMACNTRL0, _8BIT);
+					data_count >>= 1;	/* number of words */
+					outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+					CURRENT_SC->SCp.ptr += 2 * data_count;
+					CURRENT_SC->SCp.this_residual -= 2 * data_count;
+				}
+				/* wait for FIFO to get empty */
+				while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT))
+					barrier();
 
 #if defined(DEBUG_DATAO)
-        if(HOSTDATA(shpnt)->debug & debug_datao)
-          printk("fifo (%d bytes), transfered (%d bytes), ",
-                 GETPORT(FIFOSTAT), GETSTCNT());
-#endif
-
-        /* if this buffer is empty and there are more buffers left */
-        if(TESTLO(SSTAT1, PHASEMIS) &&
-           !CURRENT_SC->SCp.this_residual &&
-           CURRENT_SC->SCp.buffers_residual) {
-          /* advance to next buffer */
-          CURRENT_SC->SCp.buffers_residual--;
-          CURRENT_SC->SCp.buffer++;
-          CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address;
-          CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
-        }
-      }
-
-      if(CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) {
-        /* target leaves DATA OUT for an other phase (perhaps disconnect) */
-
-        /* data in fifos has to be resend */
-        data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
-
-        data_count += GETPORT(FIFOSTAT) ;
-        CURRENT_SC->SCp.ptr           -= data_count;
-        CURRENT_SC->SCp.this_residual += data_count;
+				if (HOSTDATA(shpnt)->debug & debug_datao)
+					printk("fifo (%d bytes), transfered (%d bytes), ",
+					  GETPORT(FIFOSTAT), GETSTCNT());
+#endif
+
+				/* if this buffer is empty and there are more buffers left */
+				if (TESTLO(SSTAT1, PHASEMIS) &&
+				    !CURRENT_SC->SCp.this_residual &&
+				    CURRENT_SC->SCp.buffers_residual) {
+					/* advance to next buffer */
+					CURRENT_SC->SCp.buffers_residual--;
+					CURRENT_SC->SCp.buffer++;
+					CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
+					CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+				}
+			}
+
+			if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) {
+				/* target leaves DATA OUT for an other phase (perhaps disconnect) */
+
+				/* data in fifos has to be resend */
+				data_count = GETPORT(SSTAT2) & (SFULL | SFCNT);
+
+				data_count += GETPORT(FIFOSTAT);
+				CURRENT_SC->SCp.ptr -= data_count;
+				CURRENT_SC->SCp.this_residual += data_count;
 #if defined(DEBUG_DATAO)
-        if(HOSTDATA(shpnt)->debug & debug_datao)
-          printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), "
-                 "transfer incomplete, resetting fifo, ",
-                 CURRENT_SC->SCp.this_residual,
-                 CURRENT_SC->SCp.buffers_residual,
-                 data_count);
-#endif
-        SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
-        CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
-        CLRBITS(DMACNTRL0, ENDMA);
-      } else {
+				if (HOSTDATA(shpnt)->debug & debug_datao)
+					printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), "
+					       "transfer incomplete, resetting fifo, ",
+					   CURRENT_SC->SCp.this_residual,
+					CURRENT_SC->SCp.buffers_residual,
+					       data_count);
+#endif
+				SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+				CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
+				CLRBITS(DMACNTRL0, ENDMA);
+			} else {
 #if defined(DEBUG_DATAO)
-        if(HOSTDATA(shpnt)->debug & debug_datao)
-          printk("waiting for SCSI fifo to get empty, ");
+				if (HOSTDATA(shpnt)->debug & debug_datao)
+					printk("waiting for SCSI fifo to get empty, ");
 #endif
-        /* wait for SCSI fifo to get empty */
-        while(TESTLO(SSTAT2, SEMPTY))
-          barrier();
+				/* wait for SCSI fifo to get empty */
+				while (TESTLO(SSTAT2, SEMPTY))
+					barrier();
 #if defined(DEBUG_DATAO)
-        if(HOSTDATA(shpnt)->debug & debug_datao)
-          printk("ok, left data (bytes=%d, buffers=%d) ",
-                 CURRENT_SC->SCp.this_residual,
-                 CURRENT_SC->SCp.buffers_residual);
-#endif
-        CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
-
-        /* transfer can be considered ended, when SCSIEN reads back zero */
-        while(TESTHI(SXFRCTL0, SCSIEN))
-          barrier();
+				if (HOSTDATA(shpnt)->debug & debug_datao)
+					printk("ok, left data (bytes=%d, buffers=%d) ",
+					   CURRENT_SC->SCp.this_residual,
+					CURRENT_SC->SCp.buffers_residual);
+#endif
+				CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
+
+				/* transfer can be considered ended, when SCSIEN reads back zero */
+				while (TESTHI(SXFRCTL0, SCSIEN))
+					barrier();
 
-        CLRBITS(DMACNTRL0, ENDMA);
-      }
+				CLRBITS(DMACNTRL0, ENDMA);
+			}
 
 #if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
-      if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr))
-        printk("sent %d data bytes, ", GETSTCNT());
+			if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr))
+				printk("sent %d data bytes, ", GETSTCNT());
 #endif
-    }
-    break;
+		}
+		break;
 
-  case P_BUSFREE:                                                /* BUSFREE */
+	case P_BUSFREE:	/* BUSFREE */
 #if defined(DEBUG_RACE)
-    leave_driver("(BUSFREE) intr");
+		leave_driver("(BUSFREE) intr");
 #endif
 #if defined(DEBUG_PHASES)
-    if(HOSTDATA(shpnt)->debug & debug_phases)
-      printk("unexpected BUS FREE, ");
+		if (HOSTDATA(shpnt)->debug & debug_phases)
+			printk("unexpected BUS FREE, ");
 #endif
-    CURRENT_SC->SCp.phase &= ~(P_MASK<<16);
+		CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
 
-    aha152x_done(shpnt, DID_ERROR << 16);         /* Don't know any better */
-    return;
-    break;
+		aha152x_done(shpnt, DID_ERROR << 16);	/* Don't know any better */
+		return;
+		break;
 
-  case P_PARITY:                              /* parity error in DATA phase */
+	case P_PARITY:		/* parity error in DATA phase */
 #if defined(DEBUG_RACE)
-    leave_driver("(DID_PARITY) intr");
+		leave_driver("(DID_PARITY) intr");
 #endif
-    printk("PARITY error in DATA phase, ");
+		printk("PARITY error in DATA phase, ");
 
-    CURRENT_SC->SCp.phase &= ~(P_MASK<<16);
+		CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
 
-    SETBITS(DMACNTRL0, INTEN);
-    aha152x_done(shpnt, DID_PARITY << 16);
-    return;
-    break;
+		SETBITS(DMACNTRL0, INTEN);
+		aha152x_done(shpnt, DID_PARITY << 16);
+		return;
+		break;
 
-  default:
-    printk("aha152x: unexpected phase\n");
-    break;
-  }
+	default:
+		printk("aha152x: unexpected phase\n");
+		break;
+	}
 
-  if(done) {
+	if (done) {
 #if defined(DEBUG_INTR)
-    if(HOSTDATA(shpnt)->debug & debug_intr)
-      printk("command done.\n");
+		if (HOSTDATA(shpnt)->debug & debug_intr)
+			printk("command done.\n");
 #endif
 #if defined(DEBUG_RACE)
-    leave_driver("(done) intr");
+		leave_driver("(done) intr");
 #endif
 
-    SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-    SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-    SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
-    
-    SETBITS(DMACNTRL0, INTEN);
-      
-    aha152x_done(shpnt,
-                 (CURRENT_SC->SCp.Status  & 0xff)
-                 | ((CURRENT_SC->SCp.Message & 0xff) << 8)
-                 | (DID_OK << 16));
+		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+
+		SETBITS(DMACNTRL0, INTEN);
+
+		aha152x_done(shpnt,
+			     (CURRENT_SC->SCp.Status & 0xff)
+			     | ((CURRENT_SC->SCp.Message & 0xff) << 8)
+			     | (DID_OK << 16));
 
 #if defined(DEBUG_RACE)
-    printk("done returned (DID_OK: Status=%x; Message=%x).\n",
-           CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message);
+		printk("done returned (DID_OK: Status=%x; Message=%x).\n",
+		       CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message);
 #endif
-    return;
-  }
-
-  if(CURRENT_SC)
-    CURRENT_SC->SCp.phase |= 1<<16;
+		return;
+	}
+	if (CURRENT_SC)
+		CURRENT_SC->SCp.phase |= 1 << 16;
 
-  SETPORT(SIMODE0, 0);
-  SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
 #if defined(DEBUG_INTR)
-  if(HOSTDATA(shpnt)->debug & debug_intr)
-    disp_enintr(shpnt);
+	if (HOSTDATA(shpnt)->debug & debug_intr)
+		disp_enintr(shpnt);
 #endif
 #if defined(DEBUG_RACE)
-  leave_driver("(PHASEEND) intr");
+	leave_driver("(PHASEEND) intr");
 #endif
 
-  SETBITS(DMACNTRL0, INTEN);
-  return;
+	SETBITS(DMACNTRL0, INTEN);
+	return;
 }
 
 /* 
@@ -2637,9 +2639,9 @@
  */
 static void aha152x_panic(struct Scsi_Host *shpnt, char *msg)
 {
-  printk("\naha152x: %s\n", msg);
-  show_queues(shpnt);
-  panic("aha152x panic");
+	printk("\naha152x: %s\n", msg);
+	show_queues(shpnt);
+	panic("aha152x panic");
 }
 
 /*
@@ -2648,166 +2650,231 @@
 static void disp_ports(struct Scsi_Host *shpnt)
 {
 #ifdef DEBUG_AHA152X
-  int s;
+	int s;
 
 #ifdef SKIP_PORTS
-  if(HOSTDATA(shpnt)->debug & debug_skipports)
-        return;
+	if (HOSTDATA(shpnt)->debug & debug_skipports)
+		return;
 #endif
 
-  printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+	printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
 
-  s=GETPORT(SCSISEQ);
-  printk("SCSISEQ (");
-  if(s & TEMODEO)     printk("TARGET MODE ");
-  if(s & ENSELO)      printk("SELO ");
-  if(s & ENSELI)      printk("SELI ");
-  if(s & ENRESELI)    printk("RESELI ");
-  if(s & ENAUTOATNO)  printk("AUTOATNO ");
-  if(s & ENAUTOATNI)  printk("AUTOATNI ");
-  if(s & ENAUTOATNP)  printk("AUTOATNP ");
-  if(s & SCSIRSTO)    printk("SCSIRSTO ");
-  printk(");");
-
-  printk(" SCSISIG (");
-  s=GETPORT(SCSISIG);
-  switch(s & P_MASK) {
-  case P_DATAO:
-    printk("DATA OUT");
-    break;
-  case P_DATAI:
-    printk("DATA IN");
-    break;
-  case P_CMD:
-    printk("COMMAND"); 
-    break;
-  case P_STATUS:
-    printk("STATUS"); 
-    break;
-  case P_MSGO:
-    printk("MESSAGE OUT");
-    break;
-  case P_MSGI:
-    printk("MESSAGE IN");
-    break;
-  default:
-    printk("*illegal*");
-    break;
-  }
-  
-  printk("); ");
-
-  printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
-
-  printk("SSTAT (");
-  s=GETPORT(SSTAT0);
-  if(s & TARGET)   printk("TARGET ");
-  if(s & SELDO)    printk("SELDO ");
-  if(s & SELDI)    printk("SELDI ");
-  if(s & SELINGO)  printk("SELINGO ");
-  if(s & SWRAP)    printk("SWRAP ");
-  if(s & SDONE)    printk("SDONE ");
-  if(s & SPIORDY)  printk("SPIORDY ");
-  if(s & DMADONE)  printk("DMADONE ");
-
-  s=GETPORT(SSTAT1);
-  if(s & SELTO)     printk("SELTO ");
-  if(s & ATNTARG)   printk("ATNTARG ");
-  if(s & SCSIRSTI)  printk("SCSIRSTI ");
-  if(s & PHASEMIS)  printk("PHASEMIS ");
-  if(s & BUSFREE)   printk("BUSFREE ");
-  if(s & SCSIPERR)  printk("SCSIPERR ");
-  if(s & PHASECHG)  printk("PHASECHG ");
-  if(s & REQINIT)   printk("REQINIT ");
-  printk("); ");
-
-
-  printk("SSTAT (");
-
-  s=GETPORT(SSTAT0) & GETPORT(SIMODE0);
-
-  if(s & TARGET)    printk("TARGET ");
-  if(s & SELDO)     printk("SELDO ");
-  if(s & SELDI)     printk("SELDI ");
-  if(s & SELINGO)   printk("SELINGO ");
-  if(s & SWRAP)     printk("SWRAP ");
-  if(s & SDONE)     printk("SDONE ");
-  if(s & SPIORDY)   printk("SPIORDY ");
-  if(s & DMADONE)   printk("DMADONE ");
-
-  s=GETPORT(SSTAT1) & GETPORT(SIMODE1);
-
-  if(s & SELTO)     printk("SELTO ");
-  if(s & ATNTARG)   printk("ATNTARG ");
-  if(s & SCSIRSTI)  printk("SCSIRSTI ");
-  if(s & PHASEMIS)  printk("PHASEMIS ");
-  if(s & BUSFREE)   printk("BUSFREE ");
-  if(s & SCSIPERR)  printk("SCSIPERR ");
-  if(s & PHASECHG)  printk("PHASECHG ");
-  if(s & REQINIT)   printk("REQINIT ");
-  printk("); ");
-
-  printk("SXFRCTL0 (");
-
-  s=GETPORT(SXFRCTL0);
-  if(s & SCSIEN)    printk("SCSIEN ");
-  if(s & DMAEN)     printk("DMAEN ");
-  if(s & CH1)       printk("CH1 ");
-  if(s & CLRSTCNT)  printk("CLRSTCNT ");
-  if(s & SPIOEN)    printk("SPIOEN ");
-  if(s & CLRCH1)    printk("CLRCH1 ");
-  printk("); ");
-
-  printk("SIGNAL (");
-
-  s=GETPORT(SCSISIG);
-  if(s & ATNI)  printk("ATNI ");
-  if(s & SELI)  printk("SELI ");
-  if(s & BSYI)  printk("BSYI ");
-  if(s & REQI)  printk("REQI ");
-  if(s & ACKI)  printk("ACKI ");
-  printk("); ");
-
-  printk("SELID (%02x), ", GETPORT(SELID));
-
-  printk("SSTAT2 (");
-
-  s=GETPORT(SSTAT2);
-  if(s & SOFFSET)  printk("SOFFSET ");
-  if(s & SEMPTY)   printk("SEMPTY ");
-  if(s & SFULL)    printk("SFULL ");
-  printk("); SFCNT (%d); ", s & (SFULL|SFCNT));
-
-  s=GETPORT(SSTAT3);
-  printk("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f);
-  
-  printk("SSTAT4 (");
-  s=GETPORT(SSTAT4);
-  if(s & SYNCERR)   printk("SYNCERR ");
-  if(s & FWERR)     printk("FWERR ");
-  if(s & FRERR)     printk("FRERR ");
-  printk("); ");
-
-  printk("DMACNTRL0 (");
-  s=GETPORT(DMACNTRL0);
-  printk("%s ", s & _8BIT      ? "8BIT"  : "16BIT");
-  printk("%s ", s & DMA        ? "DMA"   : "PIO"  );
-  printk("%s ", s & WRITE_READ ? "WRITE" : "READ" );
-  if(s & ENDMA)    printk("ENDMA ");
-  if(s & INTEN)    printk("INTEN ");
-  if(s & RSTFIFO)  printk("RSTFIFO ");
-  if(s & SWINT)    printk("SWINT ");
-  printk("); ");
-
-  printk("DMASTAT (");
-  s=GETPORT(DMASTAT);
-  if(s & ATDONE)     printk("ATDONE ");
-  if(s & WORDRDY)    printk("WORDRDY ");
-  if(s & DFIFOFULL)  printk("DFIFOFULL ");
-  if(s & DFIFOEMP)   printk("DFIFOEMP ");
-  printk(")");
+	s = GETPORT(SCSISEQ);
+	printk("SCSISEQ (");
+	if (s & TEMODEO)
+		printk("TARGET MODE ");
+	if (s & ENSELO)
+		printk("SELO ");
+	if (s & ENSELI)
+		printk("SELI ");
+	if (s & ENRESELI)
+		printk("RESELI ");
+	if (s & ENAUTOATNO)
+		printk("AUTOATNO ");
+	if (s & ENAUTOATNI)
+		printk("AUTOATNI ");
+	if (s & ENAUTOATNP)
+		printk("AUTOATNP ");
+	if (s & SCSIRSTO)
+		printk("SCSIRSTO ");
+	printk(");");
+
+	printk(" SCSISIG (");
+	s = GETPORT(SCSISIG);
+	switch (s & P_MASK) {
+	case P_DATAO:
+		printk("DATA OUT");
+		break;
+	case P_DATAI:
+		printk("DATA IN");
+		break;
+	case P_CMD:
+		printk("COMMAND");
+		break;
+	case P_STATUS:
+		printk("STATUS");
+		break;
+	case P_MSGO:
+		printk("MESSAGE OUT");
+		break;
+	case P_MSGI:
+		printk("MESSAGE IN");
+		break;
+	default:
+		printk("*illegal*");
+		break;
+	}
+
+	printk("); ");
+
+	printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
 
-  printk("\n");
+	printk("SSTAT (");
+	s = GETPORT(SSTAT0);
+	if (s & TARGET)
+		printk("TARGET ");
+	if (s & SELDO)
+		printk("SELDO ");
+	if (s & SELDI)
+		printk("SELDI ");
+	if (s & SELINGO)
+		printk("SELINGO ");
+	if (s & SWRAP)
+		printk("SWRAP ");
+	if (s & SDONE)
+		printk("SDONE ");
+	if (s & SPIORDY)
+		printk("SPIORDY ");
+	if (s & DMADONE)
+		printk("DMADONE ");
+
+	s = GETPORT(SSTAT1);
+	if (s & SELTO)
+		printk("SELTO ");
+	if (s & ATNTARG)
+		printk("ATNTARG ");
+	if (s & SCSIRSTI)
+		printk("SCSIRSTI ");
+	if (s & PHASEMIS)
+		printk("PHASEMIS ");
+	if (s & BUSFREE)
+		printk("BUSFREE ");
+	if (s & SCSIPERR)
+		printk("SCSIPERR ");
+	if (s & PHASECHG)
+		printk("PHASECHG ");
+	if (s & REQINIT)
+		printk("REQINIT ");
+	printk("); ");
+
+
+	printk("SSTAT (");
+
+	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+	if (s & TARGET)
+		printk("TARGET ");
+	if (s & SELDO)
+		printk("SELDO ");
+	if (s & SELDI)
+		printk("SELDI ");
+	if (s & SELINGO)
+		printk("SELINGO ");
+	if (s & SWRAP)
+		printk("SWRAP ");
+	if (s & SDONE)
+		printk("SDONE ");
+	if (s & SPIORDY)
+		printk("SPIORDY ");
+	if (s & DMADONE)
+		printk("DMADONE ");
+
+	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+	if (s & SELTO)
+		printk("SELTO ");
+	if (s & ATNTARG)
+		printk("ATNTARG ");
+	if (s & SCSIRSTI)
+		printk("SCSIRSTI ");
+	if (s & PHASEMIS)
+		printk("PHASEMIS ");
+	if (s & BUSFREE)
+		printk("BUSFREE ");
+	if (s & SCSIPERR)
+		printk("SCSIPERR ");
+	if (s & PHASECHG)
+		printk("PHASECHG ");
+	if (s & REQINIT)
+		printk("REQINIT ");
+	printk("); ");
+
+	printk("SXFRCTL0 (");
+
+	s = GETPORT(SXFRCTL0);
+	if (s & SCSIEN)
+		printk("SCSIEN ");
+	if (s & DMAEN)
+		printk("DMAEN ");
+	if (s & CH1)
+		printk("CH1 ");
+	if (s & CLRSTCNT)
+		printk("CLRSTCNT ");
+	if (s & SPIOEN)
+		printk("SPIOEN ");
+	if (s & CLRCH1)
+		printk("CLRCH1 ");
+	printk("); ");
+
+	printk("SIGNAL (");
+
+	s = GETPORT(SCSISIG);
+	if (s & ATNI)
+		printk("ATNI ");
+	if (s & SELI)
+		printk("SELI ");
+	if (s & BSYI)
+		printk("BSYI ");
+	if (s & REQI)
+		printk("REQI ");
+	if (s & ACKI)
+		printk("ACKI ");
+	printk("); ");
+
+	printk("SELID (%02x), ", GETPORT(SELID));
+
+	printk("SSTAT2 (");
+
+	s = GETPORT(SSTAT2);
+	if (s & SOFFSET)
+		printk("SOFFSET ");
+	if (s & SEMPTY)
+		printk("SEMPTY ");
+	if (s & SFULL)
+		printk("SFULL ");
+	printk("); SFCNT (%d); ", s & (SFULL | SFCNT));
+
+	s = GETPORT(SSTAT3);
+	printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+
+	printk("SSTAT4 (");
+	s = GETPORT(SSTAT4);
+	if (s & SYNCERR)
+		printk("SYNCERR ");
+	if (s & FWERR)
+		printk("FWERR ");
+	if (s & FRERR)
+		printk("FRERR ");
+	printk("); ");
+
+	printk("DMACNTRL0 (");
+	s = GETPORT(DMACNTRL0);
+	printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
+	printk("%s ", s & DMA ? "DMA" : "PIO");
+	printk("%s ", s & WRITE_READ ? "WRITE" : "READ");
+	if (s & ENDMA)
+		printk("ENDMA ");
+	if (s & INTEN)
+		printk("INTEN ");
+	if (s & RSTFIFO)
+		printk("RSTFIFO ");
+	if (s & SWINT)
+		printk("SWINT ");
+	printk("); ");
+
+	printk("DMASTAT (");
+	s = GETPORT(DMASTAT);
+	if (s & ATDONE)
+		printk("ATDONE ");
+	if (s & WORDRDY)
+		printk("WORDRDY ");
+	if (s & DFIFOFULL)
+		printk("DFIFOFULL ");
+	if (s & DFIFOEMP)
+		printk("DFIFOEMP ");
+	printk(")");
+
+	printk("\n");
 #endif
 }
 
@@ -2816,518 +2883,618 @@
  */
 static void disp_enintr(struct Scsi_Host *shpnt)
 {
-  int s;
+	int s;
+
+	printk("enabled interrupts (");
 
-  printk("enabled interrupts (");
-  
-  s=GETPORT(SIMODE0);
-  if(s & ENSELDO)    printk("ENSELDO ");
-  if(s & ENSELDI)    printk("ENSELDI ");
-  if(s & ENSELINGO)  printk("ENSELINGO ");
-  if(s & ENSWRAP)    printk("ENSWRAP ");
-  if(s & ENSDONE)    printk("ENSDONE ");
-  if(s & ENSPIORDY)  printk("ENSPIORDY ");
-  if(s & ENDMADONE)  printk("ENDMADONE ");
-
-  s=GETPORT(SIMODE1);
-  if(s & ENSELTIMO)    printk("ENSELTIMO ");
-  if(s & ENATNTARG)    printk("ENATNTARG ");
-  if(s & ENPHASEMIS)   printk("ENPHASEMIS ");
-  if(s & ENBUSFREE)    printk("ENBUSFREE ");
-  if(s & ENSCSIPERR)   printk("ENSCSIPERR ");
-  if(s & ENPHASECHG)   printk("ENPHASECHG ");
-  if(s & ENREQINIT)    printk("ENREQINIT ");
-  printk(")\n");
+	s = GETPORT(SIMODE0);
+	if (s & ENSELDO)
+		printk("ENSELDO ");
+	if (s & ENSELDI)
+		printk("ENSELDI ");
+	if (s & ENSELINGO)
+		printk("ENSELINGO ");
+	if (s & ENSWRAP)
+		printk("ENSWRAP ");
+	if (s & ENSDONE)
+		printk("ENSDONE ");
+	if (s & ENSPIORDY)
+		printk("ENSPIORDY ");
+	if (s & ENDMADONE)
+		printk("ENDMADONE ");
+
+	s = GETPORT(SIMODE1);
+	if (s & ENSELTIMO)
+		printk("ENSELTIMO ");
+	if (s & ENATNTARG)
+		printk("ENATNTARG ");
+	if (s & ENPHASEMIS)
+		printk("ENPHASEMIS ");
+	if (s & ENBUSFREE)
+		printk("ENBUSFREE ");
+	if (s & ENSCSIPERR)
+		printk("ENSCSIPERR ");
+	if (s & ENPHASECHG)
+		printk("ENPHASECHG ");
+	if (s & ENREQINIT)
+		printk("ENREQINIT ");
+	printk(")\n");
 }
 
 #if defined(DEBUG_RACE)
 
 static const char *should_leave;
-static int in_driver=0;
+static int in_driver = 0;
 
 /*
  * Only one routine can be in the driver at once.
  */
 static void enter_driver(const char *func)
 {
-  unsigned long flags;
+	unsigned long flags;
 
-  save_flags(flags);
-  cli();
-  printk("aha152x: entering %s() (%x)\n", func, jiffies);
-  if(in_driver) {
-    printk("%s should leave first.\n", should_leave);
-    panic("aha152x: already in driver\n");
-  }
-
-  in_driver++;
-  should_leave=func;
-  restore_flags(flags);
+	save_flags(flags);
+	cli();
+	printk("aha152x: entering %s() (%x)\n", func, jiffies);
+	if (in_driver) {
+		printk("%s should leave first.\n", should_leave);
+		panic("aha152x: already in driver\n");
+	}
+	in_driver++;
+	should_leave = func;
+	restore_flags(flags);
 }
 
 static void leave_driver(const char *func)
 {
-  unsigned long flags;
+	unsigned long flags;
 
-  save_flags(flags);
-  cli();
-  printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
-  if(!in_driver) {
-    printk("aha152x: %s already left.\n", should_leave);
-    panic("aha152x: %s already left driver.\n");
-  }
-
-  in_driver--;
-  should_leave=func;
-  restore_flags(flags);
+	save_flags(flags);
+	cli();
+	printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
+	if (!in_driver) {
+		printk("aha152x: %s already left.\n", should_leave);
+		panic("aha152x: %s already left driver.\n");
+	}
+	in_driver--;
+	should_leave = func;
+	restore_flags(flags);
 }
 #endif
 
 /*
  * Show the command data of a command
  */
-static void show_command(Scsi_Cmnd *ptr)
+static void show_command(Scsi_Cmnd * ptr)
 {
-  printk("0x%08x: target=%d; lun=%d; cmnd=(",
-         (unsigned int) ptr, ptr->target, ptr->lun);
-  
-  print_command(ptr->cmnd);
-
-  printk("); residual=%d; buffers=%d; phase |",
-         ptr->SCp.this_residual, ptr->SCp.buffers_residual);
-
-  if(ptr->SCp.phase & not_issued  )  printk("not issued|");
-  if(ptr->SCp.phase & in_selection)  printk("in selection|");
-  if(ptr->SCp.phase & disconnected)  printk("disconnected|");
-  if(ptr->SCp.phase & aborted     )  printk("aborted|");
-  if(ptr->SCp.phase & sent_ident  )  printk("send_ident|");
-  if(ptr->SCp.phase & in_other) { 
-    printk("; in other(");
-    switch((ptr->SCp.phase >> 16) & P_MASK) {
-    case P_DATAO:
-      printk("DATA OUT");
-      break;
-    case P_DATAI:
-      printk("DATA IN");
-      break;
-    case P_CMD:
-      printk("COMMAND");
-      break;
-    case P_STATUS:
-      printk("STATUS");
-      break;
-    case P_MSGO:
-      printk("MESSAGE OUT");
-      break;
-    case P_MSGI:
-      printk("MESSAGE IN");
-      break;
-    default: 
-      printk("*illegal*");
-      break;
-    }
-    printk(")");
-    if(ptr->SCp.phase & (1<<16))
-      printk("; phaseend");
-  }
-  printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+	printk("0x%08x: target=%d; lun=%d; cmnd=(",
+	       (unsigned int) ptr, ptr->target, ptr->lun);
+
+	print_command(ptr->cmnd);
+
+	printk("); residual=%d; buffers=%d; phase |",
+	       ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+
+	if (ptr->SCp.phase & not_issued)
+		printk("not issued|");
+	if (ptr->SCp.phase & in_selection)
+		printk("in selection|");
+	if (ptr->SCp.phase & disconnected)
+		printk("disconnected|");
+	if (ptr->SCp.phase & aborted)
+		printk("aborted|");
+	if (ptr->SCp.phase & sent_ident)
+		printk("send_ident|");
+	if (ptr->SCp.phase & in_other) {
+		printk("; in other(");
+		switch ((ptr->SCp.phase >> 16) & P_MASK) {
+		case P_DATAO:
+			printk("DATA OUT");
+			break;
+		case P_DATAI:
+			printk("DATA IN");
+			break;
+		case P_CMD:
+			printk("COMMAND");
+			break;
+		case P_STATUS:
+			printk("STATUS");
+			break;
+		case P_MSGO:
+			printk("MESSAGE OUT");
+			break;
+		case P_MSGI:
+			printk("MESSAGE IN");
+			break;
+		default:
+			printk("*illegal*");
+			break;
+		}
+		printk(")");
+		if (ptr->SCp.phase & (1 << 16))
+			printk("; phaseend");
+	}
+	printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
 }
- 
+
 /*
  * Dump the queued data
  */
 static void show_queues(struct Scsi_Host *shpnt)
 {
-  unsigned long flags;
-  Scsi_Cmnd *ptr;
+	unsigned long flags;
+	Scsi_Cmnd *ptr;
 
-  save_flags(flags);
-  cli();
-  printk("QUEUE STATUS:\nissue_SC:\n");
-  for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
-    show_command(ptr);
-
-  printk("current_SC:\n");
-  if(CURRENT_SC)
-    show_command(CURRENT_SC);
-  else
-    printk("none\n");
-
-  printk("disconnected_SC:\n");
-  for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
-    show_command(ptr);
-
-  disp_ports(shpnt);
-  disp_enintr(shpnt);
-  restore_flags(flags);
+	save_flags(flags);
+	cli();
+	printk("QUEUE STATUS:\nissue_SC:\n");
+	for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		show_command(ptr);
+
+	printk("current_SC:\n");
+	if (CURRENT_SC)
+		show_command(CURRENT_SC);
+	else
+		printk("none\n");
+
+	printk("disconnected_SC:\n");
+	for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		show_command(ptr);
+
+	disp_ports(shpnt);
+	disp_enintr(shpnt);
+	restore_flags(flags);
 }
 
 int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
 {
-  return(-ENOSYS);  /* Currently this is a no-op */
+	return (-ENOSYS);	/* Currently this is a no-op */
 }
 
 #undef SPRINTF
 #define SPRINTF(args...) pos += sprintf(pos, ## args)
 
-static int get_command(char *pos, Scsi_Cmnd *ptr)
+static int get_command(char *pos, Scsi_Cmnd * ptr)
 {
-  char *start = pos;
-  int i;
-  
-  SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ",
-          (unsigned int) ptr, ptr->target, ptr->lun);
-  
-  for(i=0; i<COMMAND_SIZE(ptr->cmnd[0]); i++)
-    SPRINTF("0x%02x ", ptr->cmnd[i]);
-  
-  SPRINTF("); residual=%d; buffers=%d; phase |",
-          ptr->SCp.this_residual, ptr->SCp.buffers_residual);
-  
-  if(ptr->SCp.phase & not_issued  )  SPRINTF("not issued|");
-  if(ptr->SCp.phase & in_selection)  SPRINTF("in selection|");
-  if(ptr->SCp.phase & disconnected)  SPRINTF("disconnected|");
-  if(ptr->SCp.phase & aborted     )  SPRINTF("aborted|");
-  if(ptr->SCp.phase & sent_ident  )  SPRINTF("send_ident|");
-  if(ptr->SCp.phase & in_other) { 
-    SPRINTF("; in other(");
-    switch((ptr->SCp.phase >> 16) & P_MASK) {
-    case P_DATAO:
-      SPRINTF("DATA OUT");
-      break;
-    case P_DATAI:
-      SPRINTF("DATA IN");
-      break;
-    case P_CMD:
-      SPRINTF("COMMAND");
-      break;
-    case P_STATUS:
-      SPRINTF("STATUS");
-      break;
-    case P_MSGO:
-      SPRINTF("MESSAGE OUT");
-      break;
-    case P_MSGI:
-      SPRINTF("MESSAGE IN");
-      break;
-    default: 
-      SPRINTF("*illegal*");
-      break;
-    }
-    SPRINTF(")");
-    if(ptr->SCp.phase & (1<<16))
-      SPRINTF("; phaseend");
-  }
-  SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
-  
-  return(pos-start);
+	char *start = pos;
+	int i;
+
+	SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ",
+		(unsigned int) ptr, ptr->target, ptr->lun);
+
+	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
+		SPRINTF("0x%02x ", ptr->cmnd[i]);
+
+	SPRINTF("); residual=%d; buffers=%d; phase |",
+		ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+
+	if (ptr->SCp.phase & not_issued)
+		SPRINTF("not issued|");
+	if (ptr->SCp.phase & in_selection)
+		SPRINTF("in selection|");
+	if (ptr->SCp.phase & disconnected)
+		SPRINTF("disconnected|");
+	if (ptr->SCp.phase & aborted)
+		SPRINTF("aborted|");
+	if (ptr->SCp.phase & sent_ident)
+		SPRINTF("send_ident|");
+	if (ptr->SCp.phase & in_other) {
+		SPRINTF("; in other(");
+		switch ((ptr->SCp.phase >> 16) & P_MASK) {
+		case P_DATAO:
+			SPRINTF("DATA OUT");
+			break;
+		case P_DATAI:
+			SPRINTF("DATA IN");
+			break;
+		case P_CMD:
+			SPRINTF("COMMAND");
+			break;
+		case P_STATUS:
+			SPRINTF("STATUS");
+			break;
+		case P_MSGO:
+			SPRINTF("MESSAGE OUT");
+			break;
+		case P_MSGI:
+			SPRINTF("MESSAGE IN");
+			break;
+		default:
+			SPRINTF("*illegal*");
+			break;
+		}
+		SPRINTF(")");
+		if (ptr->SCp.phase & (1 << 16))
+			SPRINTF("; phaseend");
+	}
+	SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+
+	return (pos - start);
 }
 
 static int get_ports(struct Scsi_Host *shpnt, char *pos)
 {
-  char *start = pos;
-  int s;
+	char *start = pos;
+	int s;
 
 #ifdef SKIP_PORTS
-  if(HOSTDATA(shpnt)->debug & debug_skipports)
-        return;
+	if (HOSTDATA(shpnt)->debug & debug_skipports)
+		return;
 #endif
 
-  SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+	SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+
+	s = GETPORT(SCSISEQ);
+	SPRINTF("SCSISEQ (");
+	if (s & TEMODEO)
+		SPRINTF("TARGET MODE ");
+	if (s & ENSELO)
+		SPRINTF("SELO ");
+	if (s & ENSELI)
+		SPRINTF("SELI ");
+	if (s & ENRESELI)
+		SPRINTF("RESELI ");
+	if (s & ENAUTOATNO)
+		SPRINTF("AUTOATNO ");
+	if (s & ENAUTOATNI)
+		SPRINTF("AUTOATNI ");
+	if (s & ENAUTOATNP)
+		SPRINTF("AUTOATNP ");
+	if (s & SCSIRSTO)
+		SPRINTF("SCSIRSTO ");
+	SPRINTF(");");
+
+	SPRINTF(" SCSISIG (");
+	s = GETPORT(SCSISIG);
+	switch (s & P_MASK) {
+	case P_DATAO:
+		SPRINTF("DATA OUT");
+		break;
+	case P_DATAI:
+		SPRINTF("DATA IN");
+		break;
+	case P_CMD:
+		SPRINTF("COMMAND");
+		break;
+	case P_STATUS:
+		SPRINTF("STATUS");
+		break;
+	case P_MSGO:
+		SPRINTF("MESSAGE OUT");
+		break;
+	case P_MSGI:
+		SPRINTF("MESSAGE IN");
+		break;
+	default:
+		SPRINTF("*illegal*");
+		break;
+	}
+
+	SPRINTF("); ");
+
+	SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
 
-  s=GETPORT(SCSISEQ);
-  SPRINTF("SCSISEQ (");
-  if(s & TEMODEO)     SPRINTF("TARGET MODE ");
-  if(s & ENSELO)      SPRINTF("SELO ");
-  if(s & ENSELI)      SPRINTF("SELI ");
-  if(s & ENRESELI)    SPRINTF("RESELI ");
-  if(s & ENAUTOATNO)  SPRINTF("AUTOATNO ");
-  if(s & ENAUTOATNI)  SPRINTF("AUTOATNI ");
-  if(s & ENAUTOATNP)  SPRINTF("AUTOATNP ");
-  if(s & SCSIRSTO)    SPRINTF("SCSIRSTO ");
-  SPRINTF(");");
-
-  SPRINTF(" SCSISIG (");
-  s=GETPORT(SCSISIG);
-  switch(s & P_MASK) {
-  case P_DATAO:
-    SPRINTF("DATA OUT");
-    break;
-  case P_DATAI:
-    SPRINTF("DATA IN");
-    break;
-  case P_CMD:
-    SPRINTF("COMMAND"); 
-    break;
-  case P_STATUS:
-    SPRINTF("STATUS"); 
-    break;
-  case P_MSGO:
-    SPRINTF("MESSAGE OUT");
-    break;
-  case P_MSGI:
-    SPRINTF("MESSAGE IN");
-    break;
-  default:
-    SPRINTF("*illegal*");
-    break;
-  }
-  
-  SPRINTF("); ");
-
-  SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
-
-  SPRINTF("SSTAT (");
-  s=GETPORT(SSTAT0);
-  if(s & TARGET)   SPRINTF("TARGET ");
-  if(s & SELDO)    SPRINTF("SELDO ");
-  if(s & SELDI)    SPRINTF("SELDI ");
-  if(s & SELINGO)  SPRINTF("SELINGO ");
-  if(s & SWRAP)    SPRINTF("SWRAP ");
-  if(s & SDONE)    SPRINTF("SDONE ");
-  if(s & SPIORDY)  SPRINTF("SPIORDY ");
-  if(s & DMADONE)  SPRINTF("DMADONE ");
-
-  s=GETPORT(SSTAT1);
-  if(s & SELTO)     SPRINTF("SELTO ");
-  if(s & ATNTARG)   SPRINTF("ATNTARG ");
-  if(s & SCSIRSTI)  SPRINTF("SCSIRSTI ");
-  if(s & PHASEMIS)  SPRINTF("PHASEMIS ");
-  if(s & BUSFREE)   SPRINTF("BUSFREE ");
-  if(s & SCSIPERR)  SPRINTF("SCSIPERR ");
-  if(s & PHASECHG)  SPRINTF("PHASECHG ");
-  if(s & REQINIT)   SPRINTF("REQINIT ");
-  SPRINTF("); ");
-
-
-  SPRINTF("SSTAT (");
-
-  s=GETPORT(SSTAT0) & GETPORT(SIMODE0);
-
-  if(s & TARGET)    SPRINTF("TARGET ");
-  if(s & SELDO)     SPRINTF("SELDO ");
-  if(s & SELDI)     SPRINTF("SELDI ");
-  if(s & SELINGO)   SPRINTF("SELINGO ");
-  if(s & SWRAP)     SPRINTF("SWRAP ");
-  if(s & SDONE)     SPRINTF("SDONE ");
-  if(s & SPIORDY)   SPRINTF("SPIORDY ");
-  if(s & DMADONE)   SPRINTF("DMADONE ");
-
-  s=GETPORT(SSTAT1) & GETPORT(SIMODE1);
-
-  if(s & SELTO)     SPRINTF("SELTO ");
-  if(s & ATNTARG)   SPRINTF("ATNTARG ");
-  if(s & SCSIRSTI)  SPRINTF("SCSIRSTI ");
-  if(s & PHASEMIS)  SPRINTF("PHASEMIS ");
-  if(s & BUSFREE)   SPRINTF("BUSFREE ");
-  if(s & SCSIPERR)  SPRINTF("SCSIPERR ");
-  if(s & PHASECHG)  SPRINTF("PHASECHG ");
-  if(s & REQINIT)   SPRINTF("REQINIT ");
-  SPRINTF("); ");
-
-  SPRINTF("SXFRCTL0 (");
-
-  s=GETPORT(SXFRCTL0);
-  if(s & SCSIEN)    SPRINTF("SCSIEN ");
-  if(s & DMAEN)     SPRINTF("DMAEN ");
-  if(s & CH1)       SPRINTF("CH1 ");
-  if(s & CLRSTCNT)  SPRINTF("CLRSTCNT ");
-  if(s & SPIOEN)    SPRINTF("SPIOEN ");
-  if(s & CLRCH1)    SPRINTF("CLRCH1 ");
-  SPRINTF("); ");
-
-  SPRINTF("SIGNAL (");
-
-  s=GETPORT(SCSISIG);
-  if(s & ATNI)  SPRINTF("ATNI ");
-  if(s & SELI)  SPRINTF("SELI ");
-  if(s & BSYI)  SPRINTF("BSYI ");
-  if(s & REQI)  SPRINTF("REQI ");
-  if(s & ACKI)  SPRINTF("ACKI ");
-  SPRINTF("); ");
-
-  SPRINTF("SELID (%02x), ", GETPORT(SELID));
-
-  SPRINTF("SSTAT2 (");
-
-  s=GETPORT(SSTAT2);
-  if(s & SOFFSET)  SPRINTF("SOFFSET ");
-  if(s & SEMPTY)   SPRINTF("SEMPTY ");
-  if(s & SFULL)    SPRINTF("SFULL ");
-  SPRINTF("); SFCNT (%d); ", s & (SFULL|SFCNT));
-
-  s=GETPORT(SSTAT3);
-  SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f);
-  
-  SPRINTF("SSTAT4 (");
-  s=GETPORT(SSTAT4);
-  if(s & SYNCERR)   SPRINTF("SYNCERR ");
-  if(s & FWERR)     SPRINTF("FWERR ");
-  if(s & FRERR)     SPRINTF("FRERR ");
-  SPRINTF("); ");
-
-  SPRINTF("DMACNTRL0 (");
-  s=GETPORT(DMACNTRL0);
-  SPRINTF("%s ", s & _8BIT      ? "8BIT"  : "16BIT");
-  SPRINTF("%s ", s & DMA        ? "DMA"   : "PIO"  );
-  SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ" );
-  if(s & ENDMA)    SPRINTF("ENDMA ");
-  if(s & INTEN)    SPRINTF("INTEN ");
-  if(s & RSTFIFO)  SPRINTF("RSTFIFO ");
-  if(s & SWINT)    SPRINTF("SWINT ");
-  SPRINTF("); ");
-
-  SPRINTF("DMASTAT (");
-  s=GETPORT(DMASTAT);
-  if(s & ATDONE)     SPRINTF("ATDONE ");
-  if(s & WORDRDY)    SPRINTF("WORDRDY ");
-  if(s & DFIFOFULL)  SPRINTF("DFIFOFULL ");
-  if(s & DFIFOEMP)   SPRINTF("DFIFOEMP ");
-  SPRINTF(")\n\n");
-
-  SPRINTF("enabled interrupts (");
-  
-  s=GETPORT(SIMODE0);
-  if(s & ENSELDO)    SPRINTF("ENSELDO ");
-  if(s & ENSELDI)    SPRINTF("ENSELDI ");
-  if(s & ENSELINGO)  SPRINTF("ENSELINGO ");
-  if(s & ENSWRAP)    SPRINTF("ENSWRAP ");
-  if(s & ENSDONE)    SPRINTF("ENSDONE ");
-  if(s & ENSPIORDY)  SPRINTF("ENSPIORDY ");
-  if(s & ENDMADONE)  SPRINTF("ENDMADONE ");
-
-  s=GETPORT(SIMODE1);
-  if(s & ENSELTIMO)    SPRINTF("ENSELTIMO ");
-  if(s & ENATNTARG)    SPRINTF("ENATNTARG ");
-  if(s & ENPHASEMIS)   SPRINTF("ENPHASEMIS ");
-  if(s & ENBUSFREE)    SPRINTF("ENBUSFREE ");
-  if(s & ENSCSIPERR)   SPRINTF("ENSCSIPERR ");
-  if(s & ENPHASECHG)   SPRINTF("ENPHASECHG ");
-  if(s & ENREQINIT)    SPRINTF("ENREQINIT ");
-  SPRINTF(")\n");
-  
-  return (pos-start);
+	SPRINTF("SSTAT (");
+	s = GETPORT(SSTAT0);
+	if (s & TARGET)
+		SPRINTF("TARGET ");
+	if (s & SELDO)
+		SPRINTF("SELDO ");
+	if (s & SELDI)
+		SPRINTF("SELDI ");
+	if (s & SELINGO)
+		SPRINTF("SELINGO ");
+	if (s & SWRAP)
+		SPRINTF("SWRAP ");
+	if (s & SDONE)
+		SPRINTF("SDONE ");
+	if (s & SPIORDY)
+		SPRINTF("SPIORDY ");
+	if (s & DMADONE)
+		SPRINTF("DMADONE ");
+
+	s = GETPORT(SSTAT1);
+	if (s & SELTO)
+		SPRINTF("SELTO ");
+	if (s & ATNTARG)
+		SPRINTF("ATNTARG ");
+	if (s & SCSIRSTI)
+		SPRINTF("SCSIRSTI ");
+	if (s & PHASEMIS)
+		SPRINTF("PHASEMIS ");
+	if (s & BUSFREE)
+		SPRINTF("BUSFREE ");
+	if (s & SCSIPERR)
+		SPRINTF("SCSIPERR ");
+	if (s & PHASECHG)
+		SPRINTF("PHASECHG ");
+	if (s & REQINIT)
+		SPRINTF("REQINIT ");
+	SPRINTF("); ");
+
+
+	SPRINTF("SSTAT (");
+
+	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+	if (s & TARGET)
+		SPRINTF("TARGET ");
+	if (s & SELDO)
+		SPRINTF("SELDO ");
+	if (s & SELDI)
+		SPRINTF("SELDI ");
+	if (s & SELINGO)
+		SPRINTF("SELINGO ");
+	if (s & SWRAP)
+		SPRINTF("SWRAP ");
+	if (s & SDONE)
+		SPRINTF("SDONE ");
+	if (s & SPIORDY)
+		SPRINTF("SPIORDY ");
+	if (s & DMADONE)
+		SPRINTF("DMADONE ");
+
+	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+	if (s & SELTO)
+		SPRINTF("SELTO ");
+	if (s & ATNTARG)
+		SPRINTF("ATNTARG ");
+	if (s & SCSIRSTI)
+		SPRINTF("SCSIRSTI ");
+	if (s & PHASEMIS)
+		SPRINTF("PHASEMIS ");
+	if (s & BUSFREE)
+		SPRINTF("BUSFREE ");
+	if (s & SCSIPERR)
+		SPRINTF("SCSIPERR ");
+	if (s & PHASECHG)
+		SPRINTF("PHASECHG ");
+	if (s & REQINIT)
+		SPRINTF("REQINIT ");
+	SPRINTF("); ");
+
+	SPRINTF("SXFRCTL0 (");
+
+	s = GETPORT(SXFRCTL0);
+	if (s & SCSIEN)
+		SPRINTF("SCSIEN ");
+	if (s & DMAEN)
+		SPRINTF("DMAEN ");
+	if (s & CH1)
+		SPRINTF("CH1 ");
+	if (s & CLRSTCNT)
+		SPRINTF("CLRSTCNT ");
+	if (s & SPIOEN)
+		SPRINTF("SPIOEN ");
+	if (s & CLRCH1)
+		SPRINTF("CLRCH1 ");
+	SPRINTF("); ");
+
+	SPRINTF("SIGNAL (");
+
+	s = GETPORT(SCSISIG);
+	if (s & ATNI)
+		SPRINTF("ATNI ");
+	if (s & SELI)
+		SPRINTF("SELI ");
+	if (s & BSYI)
+		SPRINTF("BSYI ");
+	if (s & REQI)
+		SPRINTF("REQI ");
+	if (s & ACKI)
+		SPRINTF("ACKI ");
+	SPRINTF("); ");
+
+	SPRINTF("SELID (%02x), ", GETPORT(SELID));
+
+	SPRINTF("SSTAT2 (");
+
+	s = GETPORT(SSTAT2);
+	if (s & SOFFSET)
+		SPRINTF("SOFFSET ");
+	if (s & SEMPTY)
+		SPRINTF("SEMPTY ");
+	if (s & SFULL)
+		SPRINTF("SFULL ");
+	SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT));
+
+	s = GETPORT(SSTAT3);
+	SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+
+	SPRINTF("SSTAT4 (");
+	s = GETPORT(SSTAT4);
+	if (s & SYNCERR)
+		SPRINTF("SYNCERR ");
+	if (s & FWERR)
+		SPRINTF("FWERR ");
+	if (s & FRERR)
+		SPRINTF("FRERR ");
+	SPRINTF("); ");
+
+	SPRINTF("DMACNTRL0 (");
+	s = GETPORT(DMACNTRL0);
+	SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
+	SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
+	SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ");
+	if (s & ENDMA)
+		SPRINTF("ENDMA ");
+	if (s & INTEN)
+		SPRINTF("INTEN ");
+	if (s & RSTFIFO)
+		SPRINTF("RSTFIFO ");
+	if (s & SWINT)
+		SPRINTF("SWINT ");
+	SPRINTF("); ");
+
+	SPRINTF("DMASTAT (");
+	s = GETPORT(DMASTAT);
+	if (s & ATDONE)
+		SPRINTF("ATDONE ");
+	if (s & WORDRDY)
+		SPRINTF("WORDRDY ");
+	if (s & DFIFOFULL)
+		SPRINTF("DFIFOFULL ");
+	if (s & DFIFOEMP)
+		SPRINTF("DFIFOEMP ");
+	SPRINTF(")\n\n");
+
+	SPRINTF("enabled interrupts (");
+
+	s = GETPORT(SIMODE0);
+	if (s & ENSELDO)
+		SPRINTF("ENSELDO ");
+	if (s & ENSELDI)
+		SPRINTF("ENSELDI ");
+	if (s & ENSELINGO)
+		SPRINTF("ENSELINGO ");
+	if (s & ENSWRAP)
+		SPRINTF("ENSWRAP ");
+	if (s & ENSDONE)
+		SPRINTF("ENSDONE ");
+	if (s & ENSPIORDY)
+		SPRINTF("ENSPIORDY ");
+	if (s & ENDMADONE)
+		SPRINTF("ENDMADONE ");
+
+	s = GETPORT(SIMODE1);
+	if (s & ENSELTIMO)
+		SPRINTF("ENSELTIMO ");
+	if (s & ENATNTARG)
+		SPRINTF("ENATNTARG ");
+	if (s & ENPHASEMIS)
+		SPRINTF("ENPHASEMIS ");
+	if (s & ENBUSFREE)
+		SPRINTF("ENBUSFREE ");
+	if (s & ENSCSIPERR)
+		SPRINTF("ENSCSIPERR ");
+	if (s & ENPHASECHG)
+		SPRINTF("ENPHASECHG ");
+	if (s & ENREQINIT)
+		SPRINTF("ENREQINIT ");
+	SPRINTF(")\n");
+
+	return (pos - start);
 }
 
 #undef SPRINTF
 #define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
 
 int aha152x_proc_info(char *buffer, char **start,
-                      off_t offset, int length, int hostno, int inout)
+		      off_t offset, int length, int hostno, int inout)
 {
-  int i;
-  char *pos = buffer;
-  struct Scsi_Host *shpnt;
-  unsigned long flags;
-  Scsi_Cmnd *ptr;
-  
-  for(i=0, shpnt= (struct Scsi_Host *) NULL; i<IRQS; i++)
-    if(aha152x_host[i] && aha152x_host[i]->host_no == hostno)
-      shpnt=aha152x_host[i];
-  
-  if(!shpnt)
-    return(-ESRCH);
-  
-  if(inout) /* Has data been written to the file ? */ 
-    return(aha152x_set_info(buffer, length, shpnt));
-  
-  SPRINTF(AHA152X_REVID "\n");
-  
-  save_flags(flags);
-  cli();
-  
-  SPRINTF("ioports 0x%04lx to 0x%04lx\n",
-          shpnt->io_port, shpnt->io_port+shpnt->n_io_port-1);
-  SPRINTF("interrupt 0x%02x\n", shpnt->irq);
-  SPRINTF("disconnection/reconnection %s\n", 
-          HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled");
-  SPRINTF("parity checking %s\n", 
-          HOSTDATA(shpnt)->parity ? "enabled" : "disabled");
-  SPRINTF("synchronous transfers %s\n", 
-          HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
-  SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
-  
-  if(HOSTDATA(shpnt)->synchronous) {
+	int i;
+	char *pos = buffer;
+	struct Scsi_Host *shpnt;
+	unsigned long flags;
+	Scsi_Cmnd *ptr;
+
+	for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++)
+		if (aha152x_host[i] && aha152x_host[i]->host_no == hostno)
+			shpnt = aha152x_host[i];
+
+	if (!shpnt)
+		return (-ESRCH);
+
+	if (inout)		/* Has data been written to the file ? */
+		return (aha152x_set_info(buffer, length, shpnt));
+
+	SPRINTF(AHA152X_REVID "\n");
+
+	save_flags(flags);
+	cli();
+
+	SPRINTF("ioports 0x%04lx to 0x%04lx\n",
+		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
+	SPRINTF("interrupt 0x%02x\n", shpnt->irq);
+	SPRINTF("disconnection/reconnection %s\n",
+		HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled");
+	SPRINTF("parity checking %s\n",
+		HOSTDATA(shpnt)->parity ? "enabled" : "disabled");
+	SPRINTF("synchronous transfers %s\n",
+		HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
+	SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
+
+	if (HOSTDATA(shpnt)->synchronous) {
 #if 0
-    SPRINTF("synchronously operating targets (tick=%ld ns):\n",
-            250000000/loops_per_sec);
-    for(i=0; i<8; i++)
-      if(HOSTDATA(shpnt)->syncrate[i]&0x7f)
-        SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n",
-                i,
-                (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2),
-                         (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*
-                         250000000/loops_per_sec,
-                           HOSTDATA(shpnt)->syncrate[i]&0x0f);
+		SPRINTF("synchronously operating targets (tick=%ld ns):\n",
+			250000000 / loops_per_sec);
+		for (i = 0; i < 8; i++)
+			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
+				SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n",
+					i,
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) *
+					250000000 / loops_per_sec,
+				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
 #else
-    SPRINTF("synchronously operating targets (tick=50 ns):\n");
-    for(i=0; i<8; i++)
-      if(HOSTDATA(shpnt)->syncrate[i]&0x7f)
-        SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n",
-                i,
-                (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2),
-                (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*50,
-                HOSTDATA(shpnt)->syncrate[i]&0x0f);
+		SPRINTF("synchronously operating targets (tick=50 ns):\n");
+		for (i = 0; i < 8; i++)
+			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
+				SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n",
+					i,
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
+				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
 #endif
-  }
-  
+	}
 #ifdef DEBUG_AHA152X
 #define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
-  
-  SPRINTF("enabled debugging options: ");
-  
-  PDEBUG(debug_skipports, "skip ports");
-  PDEBUG(debug_queue, "queue");
-  PDEBUG(debug_intr, "interrupt");
-  PDEBUG(debug_selection, "selection");
-  PDEBUG(debug_msgo, "message out");
-  PDEBUG(debug_msgi, "message in");
-  PDEBUG(debug_status, "status");
-  PDEBUG(debug_cmd, "command");
-  PDEBUG(debug_datai, "data in");
-  PDEBUG(debug_datao, "data out");
-  PDEBUG(debug_abort, "abort");
-  PDEBUG(debug_done, "done");
-  PDEBUG(debug_biosparam, "bios parameters");
-  PDEBUG(debug_phases, "phases");
-  PDEBUG(debug_queues, "queues");
-  PDEBUG(debug_reset, "reset");
-  
-  SPRINTF("\n");
-#endif
-  
-  SPRINTF("\nqueue status:\n");
-  if(ISSUE_SC) {
-    SPRINTF("not yet issued commands:\n");
-    for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
-      pos += get_command(pos, ptr);
-  } else 
-    SPRINTF("no not yet issued commands\n");
-  
-  if(CURRENT_SC) {
-    SPRINTF("current command:\n");
-    pos += get_command(pos, CURRENT_SC);
-  } else
-    SPRINTF("no current command\n");
-  
-  if(DISCONNECTED_SC) {
-    SPRINTF("disconnected commands:\n");
-    for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
-      pos += get_command(pos, ptr);
-  } else
-    SPRINTF("no disconnected commands\n");
-  
-  restore_flags(flags);
-
-  pos += get_ports(shpnt, pos);
-  
-  *start=buffer+offset;
-  if (pos - buffer < offset)
-    return 0;
-  else if (pos - buffer - offset < length)
-    return pos - buffer - offset;
-  else
-    return length;
+
+	SPRINTF("enabled debugging options: ");
+
+	PDEBUG(debug_skipports, "skip ports");
+	PDEBUG(debug_queue, "queue");
+	PDEBUG(debug_intr, "interrupt");
+	PDEBUG(debug_selection, "selection");
+	PDEBUG(debug_msgo, "message out");
+	PDEBUG(debug_msgi, "message in");
+	PDEBUG(debug_status, "status");
+	PDEBUG(debug_cmd, "command");
+	PDEBUG(debug_datai, "data in");
+	PDEBUG(debug_datao, "data out");
+	PDEBUG(debug_abort, "abort");
+	PDEBUG(debug_done, "done");
+	PDEBUG(debug_biosparam, "bios parameters");
+	PDEBUG(debug_phases, "phases");
+	PDEBUG(debug_queues, "queues");
+	PDEBUG(debug_reset, "reset");
+
+	SPRINTF("\n");
+#endif
+
+	SPRINTF("\nqueue status:\n");
+	if (ISSUE_SC) {
+		SPRINTF("not yet issued commands:\n");
+		for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+			pos += get_command(pos, ptr);
+	} else
+		SPRINTF("no not yet issued commands\n");
+
+	if (CURRENT_SC) {
+		SPRINTF("current command:\n");
+		pos += get_command(pos, CURRENT_SC);
+	} else
+		SPRINTF("no current command\n");
+
+	if (DISCONNECTED_SC) {
+		SPRINTF("disconnected commands:\n");
+		for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+			pos += get_command(pos, ptr);
+	} else
+		SPRINTF("no disconnected commands\n");
+
+	restore_flags(flags);
+
+	pos += get_ports(shpnt, pos);
+
+	*start = buffer + offset;
+	if (pos - buffer < offset)
+		return 0;
+	else if (pos - buffer - offset < length)
+		return pos - buffer - offset;
+	else
+		return length;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- v2.3.9/linux/drivers/scsi/aic7xxx/aic7xxx.reg	Wed Jun  9 16:59:15 1999
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Mon Jul  5 19:56:46 1999
@@ -845,7 +845,7 @@
 	bit	CRCENDCHKEN	0x20 /* CRC End Check Enable */
 	bit	CRCREQCHKEN	0x10
 	bit	TARGCRCENDEN	0x08 /* Enable End CRC transfer when target */
-	bit	TARGCRCCNTEN	0x40 /* Enable CRC transfer when target */
+	bit	TARGCRCCNTEN	0x04 /* Enable CRC transfer when target */
 }
 
 /*
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.9/linux/drivers/scsi/aic7xxx.c	Wed Jun  9 16:59:15 1999
+++ linux/drivers/scsi/aic7xxx.c	Mon Jul  5 19:56:46 1999
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.17"
+#define AIC7XXX_C_VERSION  "5.1.18"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -7186,7 +7186,7 @@
 static int
 acquire_seeprom(struct aic7xxx_host *p)
 {
-  int wait;
+  int count=0;
 
   /*
    * Request access of the memory port.  When access is
@@ -7196,11 +7196,10 @@
    * should be no contention.
    */
   aic_outb(p, SEEMS, SEECTL);
-  wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
-  {
-    wait--;
-    mdelay(1);  /* 1 msec */
+  while( ((aic_inb(p, SEECTL) & SEERDY) == 0) && count < 1000) {
+    mb();
+    udelay(1);
+    count++;
   }
   if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
@@ -7412,73 +7411,78 @@
 
 /*+F*************************************************************************
  * Function:
- *   write_brdctl
+ *   read_brdctl
  *
  * Description:
- *   Writes a value to the BRDCTL register.
+ *   Reads the BRDCTL register.
  *-F*************************************************************************/
-static void
-write_brdctl(struct aic7xxx_host *p, unsigned char value)
+static unsigned char
+read_brdctl(struct aic7xxx_host *p)
 {
   unsigned char brdctl;
 
   if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
   {
-    brdctl = BRDSTB;
+    brdctl = BRDRW;
     if (p->flags & AHC_CHNLB)
       brdctl |= BRDCS;
   }
   else if (p->features & AHC_ULTRA2)
-    brdctl = 0;
-  else
-    brdctl = BRDSTB | BRDCS;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  brdctl |= value;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  if (p->features & AHC_ULTRA2)
-    brdctl |= BRDSTB_ULTRA2;
-  else
-    brdctl &= ~BRDSTB;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  if (p->features & AHC_ULTRA2)
-    brdctl = 0;
+    brdctl = BRDRW_ULTRA2;
   else
-    brdctl &= ~BRDCS;
+    brdctl = BRDRW | BRDCS;
   aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
+  udelay(10);
+  return (aic_inb(p, BRDCTL));
 }
 
 /*+F*************************************************************************
  * Function:
- *   read_brdctl
+ *   write_brdctl
  *
  * Description:
- *   Reads the BRDCTL register.
+ *   Writes a value to the BRDCTL register.
  *-F*************************************************************************/
-static unsigned char
-read_brdctl(struct aic7xxx_host *p)
+static void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
 {
-  unsigned char brdctl, value;
+  unsigned char brdctl;
 
   if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
   {
-    brdctl = BRDRW;
+    brdctl = BRDSTB;
     if (p->flags & AHC_CHNLB)
       brdctl |= BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    brdctl |= value;
   }
   else if (p->features & AHC_ULTRA2)
-    brdctl = BRDRW_ULTRA2;
+  {
+    brdctl = value;
+  }
   else
-    brdctl = BRDRW | BRDCS;
+  {
+    brdctl = BRDSTB | BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    brdctl |= value;
+  }
   aic_outb(p, brdctl, BRDCTL);
-  udelay(1);
-  value = aic_inb(p, BRDCTL);
-  aic_outb(p, 0, BRDCTL);
-  udelay(1);
-  return (value);
+  udelay(4);
+  if (p->features & AHC_ULTRA2)
+    brdctl |= BRDSTB_ULTRA2;
+  else
+    brdctl &= ~BRDSTB;
+  aic_outb(p, brdctl, BRDCTL);
+  udelay(4);
+  if (p->features & AHC_ULTRA2)
+    brdctl &= ~BRDSTB_ULTRA2;
+  else
+    brdctl &= ~BRDCS;
+  aic_outb(p, brdctl, BRDCTL);
+  udelay(4);
+  read_brdctl(p);
 }
 
 /*+F*************************************************************************
@@ -7495,11 +7499,10 @@
   unsigned char brdctl;
 
   aic_outb(p, BRDRW | BRDCS, BRDCTL);
-  udelay(1);
+  udelay(4);
   aic_outb(p, 0, BRDCTL);
-  udelay(1);
+  udelay(4);
   brdctl = aic_inb(p, BRDCTL);
-  udelay(1);
   *int_50 = !(brdctl & BRDDAT5);
   *ext_present = !(brdctl & BRDDAT6);
   *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
@@ -7608,6 +7611,7 @@
     else
       max_target = 8;
     aic_outb(p, SEEMS | SEECS, SEECTL);
+    udelay(4);
     sxfrctl1 &= ~STPWEN;
     if ( (p->adapter_control & CFAUTOTERM) ||
          (p->features & AHC_ULTRA2) )
@@ -7732,25 +7736,33 @@
                  p->host_no);
       }
 
-      if (enableLVD_low != 0)
+      if (enableLVD_high != 0)
       {
-        sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_LVD;
+        brddat |= BRDDAT4;
         if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
+          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
                  p->host_no);
       }
           
-      if (enableLVD_high != 0)
+      if (enableLVD_low != 0)
       {
-        brddat |= BRDDAT4;
+        sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_LVD;
         if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
+          printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
                  p->host_no);
       }
     }
     else
     {
+      if (p->adapter_control & CFWSTERM)
+      {
+        brddat |= BRDDAT6;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                 p->host_no);
+      }
+
       if (p->adapter_control & CFSTERM)
       {
         if (p->features & AHC_ULTRA2)
@@ -7761,18 +7773,10 @@
           printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
                  p->host_no);
       }
-
-      if (p->adapter_control & CFWSTERM)
-      {
-        brddat |= BRDDAT6;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
-                 p->host_no);
-      }
     }
+    aic_outb(p, sxfrctl1, SXFRCTL1);
     write_brdctl(p, brddat);
     release_seeprom(p);
-    aic_outb(p, sxfrctl1, SXFRCTL1);
   }
 }
 
@@ -8086,7 +8090,7 @@
     /* Select channel B */
     aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
 
-    term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+    term = (aic_inb(p, SXFRCTL1) & STPWEN);
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
@@ -8100,11 +8104,15 @@
     aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
   }
 
-  term = ((p->flags & AHC_TERM_ENB_SE_LOW) != 0) ? STPWEN : 0;
   if (p->features & AHC_ULTRA2)
+  {
     aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
+  }
   else
+  {
     aic_outb(p, p->scsi_id, SCSIID);
+  }
+  term = (aic_inb(p, SXFRCTL1) & STPWEN);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
   aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
@@ -8794,27 +8802,33 @@
     }
     if (p->flags & AHC_NEWEEPROM_FMT)
     {
-      if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
-          !(p->features & AHC_ULTRA2) )
+      if ( !(p->features & AHC_ULTRA2) )
       {
         /*
          * I know of two different Ultra BIOSes that do this differently.
          * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
-         * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+         * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s
          * while on the IBM Netfinity 5000 they want the same thing
          * to be something else, while flags[i] & CFXFER == 0x03 and
-         * SYNCISULTRA false should be 40MByte/s.  So, we set both to
+         * SYNCHISULTRA false should be 40MByte/s.  So, we set both to
          * 40MByte/s and the lower speeds be damned.  People will have
          * to select around the conversely mapped lower speeds in order
          * to select lower speeds on these boards.
          */
-        if ((sc->device_flags[i] & (CFXFER)) == 0x03)
+        if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+            ((sc->device_flags[i] & CFXFER) == 0x03) )
         {
           sc->device_flags[i] &= ~CFXFER;
           sc->device_flags[i] |= CFSYNCHISULTRA;
         }
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= mask;
+        }
       }
-      if (sc->device_flags[i] & CFSYNCHISULTRA)
+      else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+                 (p->features & AHC_ULTRA2) &&
+		 (sc->device_flags[i] & CFSYNCHISULTRA) )
       {
         p->ultraenb |= mask;
       }
@@ -9290,6 +9304,10 @@
        AHC_AIC7860_FE,                                       7,
        32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
        32, C46 },
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.3.9/linux/drivers/scsi/aic7xxx_reg.h	Wed Jun  9 16:59:15 1999
+++ linux/drivers/scsi/aic7xxx_reg.h	Mon Jul  5 19:56:46 1999
@@ -459,11 +459,11 @@
 
 #define	CRCCONTROL1     		0x9d
 #define		CRCONSEEN       	0x80
-#define		TARGCRCCNTEN    	0x40
 #define		CRCVALCHKEN     	0x40
 #define		CRCENDCHKEN     	0x20
 #define		CRCREQCHKEN     	0x10
 #define		TARGCRCENDEN    	0x08
+#define		TARGCRCCNTEN    	0x04
 
 #define	SCSIPHASE       		0x9e
 #define		SP_STATUS       	0x20
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- v2.3.9/linux/drivers/scsi/atp870u.c	Wed Feb 24 16:27:54 1999
+++ linux/drivers/scsi/atp870u.c	Mon Jul  5 19:56:46 1999
@@ -3,7 +3,9 @@
  *
  *  Copyright (C) 1997	Wu Ching Chen
  *  2.1.x update (C) 1998  Krzysztof G. Baranowski
- *
+ *   
+ * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes 
+ * 
  */
 
 #include <linux/module.h>
@@ -17,6 +19,7 @@
 #include <linux/proc_fs.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 #include <linux/pci.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -60,6 +63,7 @@
 
 static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
+	 unsigned long flags;
     unsigned short int	tmpcip,id;
     unsigned char	i,j,h,tarid,lun;
     unsigned char  *prd;
@@ -364,7 +368,10 @@
 	     outb(0x80,tmport);
 	  }   */
 go_42:
+	  spin_lock_irqsave(&io_request_lock, flags);
 	  (*workrequ->scsi_done)(workrequ);
+	  spin_unlock_irqrestore(&io_request_lock, flags);
+
 	  curr_req[h][tarid]=0;
 	  workingu[h]--;
 	  if (wide_idu[h] != 0)
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- v2.3.9/linux/drivers/scsi/constants.c	Sun Dec 21 17:04:48 1997
+++ linux/drivers/scsi/constants.c	Mon Jul  5 19:56:46 1999
@@ -1,6 +1,8 @@
 /* 
  * ASCII values for a number of symbolic constants, printing functions,
  * etc.
+ * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
+ *
  */
 
 #define __NO_VERSION__
@@ -37,7 +39,7 @@
 /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
 /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
 /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
-/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve",
 /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
 /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
 /* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
@@ -46,37 +48,57 @@
 
 static const char *group_1_commands[] = {
 /* 20-22 */  unknown, unknown, unknown,
-/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", 
-/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, 
+/* 23-28 */ unknown, "Define window parameters", "Read Capacity", 
+            unknown, unknown, "Read (10)", 
+/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", 
+            "Read updated block", 
 /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", 
 /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
 /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", 
-/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", 
+/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", 
+            "Read Buffer", 
 /* 3d-3f */ "Update Block", "Read Long",  "Write Long",
 };
 
 
 static const char *group_2_commands[] = {
 /* 40-41 */ "Change Definition", "Write Same", 
-/* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, 
-/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown,
+/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", 
+            "Play audio (10)", unknown, "Play audio msf",
+            "Play audio track/index", 
+/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", 
+            "Log Select", "Log Sense", unknown, unknown,
 /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
 /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
 /* 5c-5f */ unknown, unknown, unknown,
 };
 
 
+/* The following are 12 byte commands in group 5 */
+static const char *group_5_commands[] = {
+/* a0-a5 */ unknown, unknown, unknown, unknown, unknown,
+            "Move medium/play audio(12)",
+/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", 
+/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, 
+            "Write and verify(12)", 
+/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
+/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown,
+/* b5-b6 */ "Request volume element address", "Send volume tag",
+/* b7-b9 */ "Read defect data(12)", "Read element status", unknown,
+/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown,
+};
+
+
 
 #define group(opcode) (((opcode) >> 5) & 7)
 
 #define RESERVED_GROUP  0
 #define VENDOR_GROUP    1
-#define NOTEXT_GROUP    2
 
 static const char **commands[] = {
     group_0_commands, group_1_commands, group_2_commands, 
     (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
-    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    group_5_commands, (const char **) VENDOR_GROUP, 
     (const char **) VENDOR_GROUP
 };
 
@@ -89,9 +111,6 @@
     case RESERVED_GROUP:
 	printk("%s(0x%02x) ", reserved, opcode); 
 	break;
-    case NOTEXT_GROUP:
-	printk("%s(0x%02x) ", unknown, opcode); 
-	break;
     case VENDOR_GROUP:
 	printk("%s(0x%02x) ", vendor, opcode); 
 	break;
@@ -119,15 +138,18 @@
 
 #if (CONSTANTS & CONST_STATUS)
 static const char * statuses[] = {
-/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", 
-/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, 
-/* a-d */ "Intermediate Good", unknown, "Reservation Conflict", unknown,
-/* e-f */ unknown, unknown,
+/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", 
+/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, 
+/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict",
+/* d-10 */ unknown, unknown, unknown, unknown,
+/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full",
+/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown,
+/* 1b-1f */ unknown, unknown, unknown, unknown, unknown,
 };
 #endif
 
 void print_status (int status) {
-    status = (status >> 1) & 0xf;
+    status = (status >> 1) & 0x1f;
 #if (CONSTANTS & CONST_STATUS)
     printk("%s ",statuses[status]);
 #else
@@ -405,8 +427,10 @@
            s = sizeof(SCpnt->sense_buffer);
 	
 	if (!valid)
-	    printk("extra data not valid ");
-	
+	    printk("[valid=0] ");
+	printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) |
+	       (sense_buffer[4] << 16) | (sense_buffer[5] << 8) |
+	       sense_buffer[6]));
 	if (sense_buffer[2] & 0x80)
            printk( "FMK ");	/* current command has read a filemark */
 	if (sense_buffer[2] & 0x40)
@@ -427,7 +451,7 @@
 	    error = "Invalid";
 	}
 	
-	printk("%s error ", error);
+	printk("%s ", error);
 	
 #if (CONSTANTS & CONST_SENSE)
 	printk( "%s%s: sense key %s\n", devclass,
@@ -603,7 +627,8 @@
 #if (CONSTANTS & CONST_HOST)
 static const char * hostbyte_table[]={
 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", 
-"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL};
+"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
+"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL};
 
 void print_hostbyte(int scsiresult)
 {   static int maxcode=0;
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c
--- v2.3.9/linux/drivers/scsi/i60uscsi.c	Wed Feb 24 16:27:54 1999
+++ linux/drivers/scsi/i60uscsi.c	Mon Jul  5 20:36:12 1999
@@ -765,11 +765,11 @@
 		if (inia100_adpt[i].ADPT_BIOS < wBIOS)
 			continue;
 		if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
-			if (inia100_adpt[i].ADPT_BASE == wBASE)
+			if (inia100_adpt[i].ADPT_BASE == wBASE) {
 				if (inia100_adpt[i].ADPT_Bus != 0xFF)
 					return (FAILURE);
-				else if (inia100_adpt[i].ADPT_BASE < wBASE)
-					continue;
+			} else if (inia100_adpt[i].ADPT_BASE < wBASE)
+				continue;
 		}
 		for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
 			inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE;
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.3.9/linux/drivers/scsi/ide-scsi.c	Thu May 13 23:23:27 1999
+++ linux/drivers/scsi/ide-scsi.c	Tue Jul  6 19:08:33 1999
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.6		Jan  27, 1998
+ * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
  *
- * Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
  */
 
 /*
@@ -25,10 +25,11 @@
  *                       Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
  * Ver 0.7   Dec 04 98   Ignore commands where lun != 0 to avoid multiple
  *                        detection of devices with CONFIG_SCSI_MULTI_LUN
- * Ver 0.8   Feb 05 99   Optical media need translation too. 
+ * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7.
+ * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM.
  */
 
-#define IDESCSI_VERSION "0.6"
+#define IDESCSI_VERSION "0.9"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -631,9 +632,13 @@
 {
 	ide_drive_t *drive = idescsi_drives[dev->id];
 	idescsi_scsi_t *scsi = drive->driver_data;
+	int enable = (int) arg;
 
 	if (cmd == SG_SET_TRANSFORM) {
-		set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+		if (enable)
+			set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+		else
+			clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 		return 0;
 	} else if (cmd == SG_GET_TRANSFORM)
 		return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg);
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.3.9/linux/drivers/scsi/ini9100u.c	Tue Jan 19 11:23:23 1999
+++ linux/drivers/scsi/ini9100u.c	Mon Jul  5 20:35:18 1999
@@ -109,19 +109,13 @@
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
@@ -129,39 +123,28 @@
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "ini9100u.h"
 #include <linux/stat.h>
-#include <linux/malloc.h>
 #include <linux/config.h>
 
 #else
 
-#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
+#include <asm/system.h>
+#include "../block/blk.h"
+#endif
+
+#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "ini9100u.h"
-#endif
-
-#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-#endif
 
 #ifdef DEBUG_i91u
 unsigned int i91u_debug = DEBUG_DEFAULT;
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.3.9/linux/drivers/scsi/inia100.c	Wed Feb 24 16:27:54 1999
+++ linux/drivers/scsi/inia100.c	Mon Jul  5 20:35:18 1999
@@ -73,19 +73,13 @@
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
@@ -93,33 +87,27 @@
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "inia100.h"
 #include <linux/stat.h>
-#include <linux/malloc.h>
-
 
 #else
 
-#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
+#include <asm/system.h>
+#include "../block/blk.h"
+#endif
+
+#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "inia100.h"
-#endif
 
 #ifdef MODULE
 Scsi_Host_Template driver_template = INIA100;
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.3.9/linux/drivers/scsi/megaraid.c	Tue May 11 15:48:45 1999
+++ linux/drivers/scsi/megaraid.c	Mon Jul  5 20:35:18 1999
@@ -129,9 +129,7 @@
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
 
-#include <linux/sched.h>
 #include <linux/stat.h>
-#include <linux/malloc.h>	/* for kmalloc() */
 #if LINUX_VERSION_CODE < 0x20100
 #include <linux/bios32.h>
 #else
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c
--- v2.3.9/linux/drivers/scsi/mvme16x.c	Thu Jul 30 11:17:11 1998
+++ linux/drivers/scsi/mvme16x.c	Mon Jul  5 20:35:18 1999
@@ -18,7 +18,6 @@
 #include "hosts.h"
 #include "53c7xx.h"
 #include "mvme16x.h"
-#include "asm/mvme16xhw.h"
 
 #include<linux/stat.h>
 
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.3.9/linux/drivers/scsi/ncr53c8xx.c	Mon Apr 12 09:51:04 1999
+++ linux/drivers/scsi/ncr53c8xx.c	Sun Jul  4 09:53:12 1999
@@ -9858,7 +9858,7 @@
 	}
 
 	if (!latency_timer) {
-		latency_timer = 128;
+		latency_timer = 64;
 		if (initverbose >= 2)
 			printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
 		pcibios_write_config_byte(bus, device_fn,
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c
--- v2.3.9/linux/drivers/scsi/pas16.c	Sat Apr 11 11:13:25 1998
+++ linux/drivers/scsi/pas16.c	Mon Jul  5 20:35:18 1999
@@ -577,6 +577,5 @@
 /* Eventually this will go into an include file, but this will be later */
 Scsi_Host_Template driver_template = MV_PAS16;
 
-#include <linux/module.h>
 #include "scsi_module.c"
 #endif
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.3.9/linux/drivers/scsi/ppa.c	Fri May  7 10:57:42 1999
+++ linux/drivers/scsi/ppa.c	Thu Jul  1 14:22:57 1999
@@ -158,14 +158,14 @@
 	 */
 	ppa_hosts[i].mode = PPA_NIBBLE;
 
-	if (modes & PARPORT_MODE_PCPS2)
+	if (modes & PARPORT_MODE_TRISTATE)
 	    ppa_hosts[i].mode = PPA_PS2;
 
-	if (modes & PARPORT_MODE_PCECPPS2) {
+	if (modes & PARPORT_MODE_ECP) {
 	    w_ecr(ppb, 0x20);
 	    ppa_hosts[i].mode = PPA_PS2;
 	}
-	if (modes & PARPORT_MODE_PCECPEPP)
+	if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP))
 	    w_ecr(ppb, 0x80);
 
 	/* Done configuration */
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.3.9/linux/drivers/scsi/qlogicfc.c	Thu Apr 15 05:42:43 1999
+++ linux/drivers/scsi/qlogicfc.c	Mon Jul  5 19:58:24 1999
@@ -155,16 +155,16 @@
 #endif				/* DEBUG ISP2100_INTR */
 
 
-#if defined(__i386__)
-#define virt_to_bus_low32(x)   virt_to_bus(x)
-#define virt_to_bus_high32(x)  0x0
-#define bus_to_virt_low32(x)   bus_to_virt(x)
-#define bus_to_virt_high32(x)  0x0
-#elif defined(__alpha__)
+#if BITS_PER_LONG > 32
 #define virt_to_bus_low32(x)   ((u32) (0xffffffff & virt_to_bus(x)))
 #define virt_to_bus_high32(x)  ((u32) (0xffffffff & (virt_to_bus(x)>>32)))
 #define bus_to_virt_low32(x)   ((u32) (0xffffffff & bus_to_virt(x)))
 #define bus_to_virt_high32(x)  ((u32) (0xffffffff & (bus_to_virt(x)>>32)))
+#else
+#define virt_to_bus_low32(x)   virt_to_bus(x)
+#define virt_to_bus_high32(x)  0x0
+#define bus_to_virt_low32(x)   bus_to_virt(x)
+#define bus_to_virt_high32(x)  0x0
 #endif
 
 #define ISP2100_REV_ID	1
@@ -228,19 +228,47 @@
 };
 
 /* entry header type commands */
+#if BITS_PER_LONG > 32
 #define ENTRY_COMMAND		0x19
 #define ENTRY_CONTINUATION	0x0a
+#else
+#define ENTRY_COMMAND		0x11
+#define ENTRY_CONTINUATION	0x02
+#endif
 #define ENTRY_STATUS		0x03
 #define ENTRY_MARKER		0x04
 
+
 /* entry header flag definitions */
 #define EFLAG_BUSY		2
 #define EFLAG_BAD_HEADER	4
 #define EFLAG_BAD_PAYLOAD	8
 
+#if BITS_PER_LONG > 32
+struct dataseg {
+	u_int d_base;
+	u_int d_base_hi;
+	u_int d_count;
+};
+
+struct Command_Entry {
+	struct Entry_header hdr;
+	u_int handle;
+	u_char target_lun;
+	u_char target_id;
+	u_short rsvd1;
+	u_short control_flags;
+	u_short rsvd2;
+	u_short time_out;
+	u_short segment_cnt;
+	u_char cdb[16];
+	u_int total_byte_cnt;
+	struct dataseg dataseg[DATASEGS_PER_COMMAND];
+};
+
+#else
 struct dataseg {
-	u_int d_base_lo;
-	u_int d_base_high;
+	u_int d_base;
 	u_int d_count;
 };
 
@@ -256,9 +284,12 @@
 	u_short segment_cnt;
 	u_char cdb[16];
 	u_int total_byte_cnt;
-	struct dataseg dataseg[2];
+	struct dataseg dataseg[DATASEGS_PER_COMMAND];
 };
 
+#endif
+
+
 /* command entry control flag definitions */
 #define CFLAG_NODISC		0x01
 #define CFLAG_HEAD_TAG		0x02
@@ -281,10 +312,18 @@
 	u_char cdb[44];
 };
 
+#if BITS_PER_LONG > 32
+struct Continuation_Entry {
+	struct Entry_header hdr;
+	struct dataseg dataseg[DATASEGS_PER_CONT];
+};
+#else
 struct Continuation_Entry {
 	struct Entry_header hdr;
-	struct dataseg dataseg[5];
+        u32 rsvd;
+	struct dataseg dataseg[DATASEGS_PER_CONT];
 };
+#endif
 
 struct Marker_Entry {
 	struct Entry_header hdr;
@@ -549,7 +588,7 @@
 	u_int response_high;
 	u_short sub_len;
 	u_short res2;
-	u_short data[22];
+	u_char data[44];
 };
 
 /* address of instance of this struct is passed to adapter to initialize things
@@ -586,9 +625,17 @@
 #if ISP2100_FABRIC
 #define QLOGICFC_MAX_ID    0xff
 #else
-#define QLOGICFC_MAX_ID    0x80
+#define QLOGICFC_MAX_ID    0x7d
 #endif
 
+#define QLOGICFC_MAX_LOOP_ID 0x7d
+
+/* adapter_state values */
+#define AS_FIRMWARE_DEAD      -1
+#define AS_LOOP_DOWN           0
+#define AS_LOOP_GOOD           1
+#define AS_REDO_PORTDB         2
+
 struct isp2100_hostdata {
 	u_char revision;
 	struct pci_dev *pci_dev;
@@ -602,7 +649,7 @@
 	char res[RES_QUEUE_LEN + 1][QUEUE_ENTRY_LEN];
 	char req[QLOGICFC_REQ_QUEUE_LEN + 1][QUEUE_ENTRY_LEN];
 	struct init_cb control_block;
-	int loop_up;
+	int adapter_state;
 	unsigned long int tag_ages[126];
 	Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1];
 	unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1];
@@ -611,6 +658,7 @@
 	u64 wwn;
 	u_int port_id;
 	u_char queued;
+	u_char host_id;
 };
 
 
@@ -643,7 +691,9 @@
 static void isp2100_print_scsi_cmd(Scsi_Cmnd *);
 #endif
 
+#if DEBUG_ISP2100_INTR
 static void isp2100_print_status_entry(struct Status_Entry *);
+#endif
 
 static struct proc_dir_entry proc_scsi_isp2100 =
 {
@@ -693,7 +743,7 @@
 		hostdata->queued = 0;
 		/* set up the control block */
 		hostdata->control_block.version = 0x0f;
-		hostdata->control_block.firm_opts = 0x010c;
+		hostdata->control_block.firm_opts = 0x0108;
 		hostdata->control_block.max_frame_len = 2048;
 		hostdata->control_block.max_iocb = 256;
 		hostdata->control_block.exec_throttle = 8;
@@ -711,8 +761,9 @@
 		hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req);
 		hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req);
 
-		hostdata->loop_up = 0;
-
+		hostdata->adapter_state = AS_LOOP_DOWN;
+		hostdata->host_id = hosts;
+		
 		if (isp2100_init(host) || isp2100_reset_hardware(host)) {
 			scsi_unregister(host);
 			continue;
@@ -720,15 +771,15 @@
 		host->this_id = 0;
 
 		if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) {
-			printk("qlogicfc : interrupt %d already in use\n",
-			       host->irq);
+			printk("qlogicfc%d : interrupt %d already in use\n",
+			       hostdata->host_id, host->irq);
 			scsi_unregister(host);
 			continue;
 		}
 		if (check_region(host->io_port, 0xff)) {
-			printk("qlogicfc : i/o region 0x%lx-0x%lx already "
+			printk("qlogicfc%d : i/o region 0x%lx-0x%lx already "
 			       "in use\n",
-			       host->io_port, host->io_port + 0xff);
+			       hostdata->host_id, host->io_port, host->io_port + 0xff);
 			free_irq(host->irq, host);
 			scsi_unregister(host);
 			continue;
@@ -739,15 +790,11 @@
 		outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
 		isp2100_enable_irqs(host);
 		/* wait for the loop to come up */
-		for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->loop_up == 0;)
+		for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;)
 			barrier();
 
-		if (hostdata->loop_up == 0) {
-			printk("qlogicfc: loop is not up\n");
-			release_region(host->io_port, 0xff);
-			free_irq(host->irq, host);
-			scsi_unregister(host);
-			continue;
+		if (hostdata->adapter_state == AS_LOOP_DOWN) {
+			printk("qlogicfc%d : loop is not up\n", hostdata->host_id);
 		}
 		hosts++;
 	}
@@ -790,7 +837,7 @@
 		isp2100_mbox_command(host, param);
 
 		if (param[0] != MBOX_COMMAND_COMPLETE) {
-			printk("logout failed %x  %x\n", i, param[0]);
+			printk("qlogicfc%d : logout failed %x  %x\n", hostdata->host_id, i, param[0]);
 		}
 	}
 #endif
@@ -807,13 +854,14 @@
 		temp[0].wwn = hostdata->wwn;
 	}
 	else {
-	        printk("qlogicfc: error getting scsi id.\n");
+	        printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id);
 	}
 
-	for (i = 1, j = 1; i <= QLOGICFC_MAX_ID; i++) {
-	        temp[i].loop_id = temp[0].loop_id;
-
-		param[0] = MBOX_GET_PORT_NAME;
+        for (i = 0; i <=QLOGICFC_MAX_ID; i++)
+                temp[i].loop_id = temp[0].loop_id;
+   
+        for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) {
+                param[0] = MBOX_GET_PORT_NAME;
 		param[1] = (i << 8) & 0xff00;
 
 		isp2100_mbox_command(host, param);
@@ -856,7 +904,7 @@
 				}
 			}
 			if (j == QLOGICFC_MAX_ID + 1)
-				printk("qlogicfc.c: Too many scsi devices, no more room in port map.\n");
+				printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id);
 			if (!hostdata->port_db[j].wwn) {
 				hostdata->port_db[j].loop_id = temp[i].loop_id;
 				hostdata->port_db[j].wwn = temp[i].wwn;
@@ -874,14 +922,18 @@
 
 #if ISP2100_FABRIC
 
-int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int j)
+#define FABRIC_PORT          0x7e
+#define FABRIC_CONTROLLER    0x7f
+#define FABRIC_SNS           0x80
+
+int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id)
 {
 
 	u_short param[8];
 	u64 wwn;
 	int done = 0;
 	u_short loop_id = 0x81;
-	u_short scsi_id = j;
+	u_short scsi_id = cur_scsi_id;
 	u_int port_id;
 	struct sns_cb req;
 	u_char sns_response[608];
@@ -889,18 +941,42 @@
 
 	hostdata = (struct isp2100_hostdata *) host->hostdata;
 
-	DEBUG_FABRIC(printk("qlogicfc.c: Checking for a fabric.\n"));
+	DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id));
 	param[0] = MBOX_GET_PORT_NAME;
-	param[1] = 0x7E00;
+	param[1] = (u16)FABRIC_PORT << 8;
 
 	isp2100_mbox_command(host, param);
 
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		DEBUG_FABRIC(printk("fabric check result %x\n", param[0]));
+		DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0]));
 		return 0;
 	}
-	printk("qlogicfc.c: Fabric found.\n");
+	printk("qlogicfc%d : Fabric found.\n", hostdata->host_id);
+
 
+	memset(&req, 0, sizeof(req));
+	
+	req.len = 8;
+	req.response_low = virt_to_bus_low32(sns_response);
+	req.response_high = virt_to_bus_high32(sns_response);
+	req.sub_len = 22;
+	req.data[0] = 0x17;
+	req.data[1] = 0x02;
+	req.data[8] = (u_char) (hostdata->port_id & 0xff);
+	req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
+	req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
+	req.data[13] = 0x01;
+	param[0] = MBOX_SEND_SNS;
+	param[1] = 30;
+	param[2] = virt_to_bus_low32(&req) >> 16;
+	param[3] = virt_to_bus_low32(&req);
+	param[6] = virt_to_bus_high32(&req) >> 16;
+	param[7] = virt_to_bus_high32(&req);
+	
+	isp2100_mbox_command(host, param);
+	
+	if (param[0] != MBOX_COMMAND_COMPLETE)
+	        printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);	       
 
 	port_id = hostdata->port_id;
 	while (!done) {
@@ -910,9 +986,11 @@
 		req.response_low = virt_to_bus_low32(sns_response);
 		req.response_high = virt_to_bus_high32(sns_response);
 		req.sub_len = 6;
-		req.data[0] = 0x0100;
-		req.data[4] = (u_short) (port_id & 0xffff);
-		req.data[5] = (u_short) (port_id >> 16 & 0xffff);
+		req.data[0] = 0x00;
+		req.data[1] = 0x01;
+		req.data[8] = (u_char) (port_id & 0xff);
+		req.data[9] = (u_char) (port_id >> 8 & 0xff);
+		req.data[10] = (u_char) (port_id >> 16 & 0xff);
 
 		param[0] = MBOX_SEND_SNS;
 		param[1] = 14;
@@ -924,7 +1002,7 @@
 		isp2100_mbox_command(host, param);
 
 		if (param[0] == MBOX_COMMAND_COMPLETE) {
-			DEBUG_FABRIC(printk("found node %02x%02x%02x%02x%02x%02x%02x%02x ", sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27]));
+			DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27]));
 			DEBUG_FABRIC(printk("  port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19]));
 			port_id = ((u_int) sns_response[17]) << 16;
 			port_id |= ((u_int) sns_response[18]) << 8;
@@ -938,7 +1016,7 @@
 			wwn |= ((u64) sns_response[26]) << 8;
 			wwn |= ((u64) sns_response[27]);
 			if (hostdata->port_id >> 8 != port_id >> 8) {
-				DEBUG_FABRIC(printk("adding a fabric port: %x\n", port_id));
+				DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id));
 				param[0] = MBOX_PORT_LOGIN;
 				param[1] = loop_id << 8;
 				param[2] = (u_short) (port_id >> 16);
@@ -952,15 +1030,15 @@
 					loop_id++;
 					scsi_id++;
 				} else {
-					printk("qlogicfc.c: Error performing port login %x\n", param[0]);
-					DEBUG_FABRIC(printk("loop_id: %x\n", loop_id));
+					printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]);
+					DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id));
 				}
 
 			}
 			if (hostdata->port_id == port_id)
 				done = 1;
 		} else {
-			printk("qlogicfc.c: Get All Next failed %x.\n", param[0]);
+			printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]);
 			return 0;
 		}
 	}
@@ -1034,15 +1112,16 @@
 
 	DEBUG(isp2100_print_scsi_cmd(Cmnd));
 
-	if (hostdata->loop_up == 2) {
-		hostdata->loop_up = 1;
+	if (hostdata->adapter_state == AS_REDO_PORTDB) {
+		hostdata->adapter_state = AS_LOOP_GOOD;
 		isp2100_make_portdb(host);
+		printk("qlogicfc%d : Port Database\n", hostdata->host_id);
 		for (i = 0; hostdata->port_db[i].wwn != 0; i++) {
-			DEBUG(printk("wwn: %08x%08x  scsi_id: %x  loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id));
+			printk("wwn: %08x%08x  scsi_id: %x  loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id);
 		}
 	}
-	if (hostdata->loop_up == -1) {
-		printk("qlogicfc.c: The firmware is dead, just return.\n");
+	if (hostdata->adapter_state == AS_FIRMWARE_DEAD) {
+		printk("qlogicfc%d : The firmware is dead, just return.\n", hostdata->host_id);
 		host->max_id = 0;
 		return 0;
 	}
@@ -1050,13 +1129,13 @@
 	out_ptr = inw(host->io_port + MBOX4);
 	in_ptr = hostdata->req_in_ptr;
 
-	DEBUG(printk("qlogicfc : request queue depth %d\n",
+	DEBUG(printk("qlogicfc%d : request queue depth %d\n", hostdata->host_id,
 		     REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
 
 	cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0];
 	in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
 	if (in_ptr == out_ptr) {
-		DEBUG(printk("qlogicfc : request queue overflow\n"));
+		DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id));
 		return 1;
 	}
 	if (hostdata->send_marker) {
@@ -1064,7 +1143,7 @@
 
 		TRACE("queue marker", in_ptr, 0);
 
-		DEBUG(printk("qlogicfc : adding marker entry\n"));
+		DEBUG(printk("qlogicfc%d : adding marker entry\n", hostdata->host_id));
 		marker = (struct Marker_Entry *) cmd;
 		memset(marker, 0, sizeof(struct Marker_Entry));
 
@@ -1077,7 +1156,7 @@
 		if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) {
 			outw(in_ptr, host->io_port + MBOX4);
 			hostdata->req_in_ptr = in_ptr;
-			DEBUG(printk("qlogicfc : request queue overflow\n"));
+			DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id));
 			return 1;
 		}
 		cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0];
@@ -1094,8 +1173,15 @@
 		cmd->handle = i;
 		hostdata->handle_ptrs[i] = Cmnd;
 		hostdata->handle_serials[i] = Cmnd->serial_number;
-	} else
-		printk("qlogicfc: no handle slots, this should not happen.\n");
+	} else {
+		printk("qlogicfc%d : no handle slots, this should not happen.\n", hostdata->host_id);
+		printk("hostdata->queued is %x, in_ptr: %x\n", hostdata->queued, in_ptr);
+		for (i = 0; i <= QLOGICFC_REQ_QUEUE_LEN; i++){
+			if (!hostdata->handle_ptrs[i]){
+				printk("slot %d has %p\n", i, hostdata->handle_ptrs[i]);
+			}
+		}
+	}
 
 	cmd->hdr.entry_type = ENTRY_COMMAND;
 	cmd->hdr.entry_cnt = 1;
@@ -1106,7 +1192,7 @@
 	cmd->target_id = Cmnd->target;
 #endif
 	cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen;
-	cmd->time_out = (SCSI_TIMEOUT / HZ) * 5;
+	cmd->time_out = 0;
 	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
 
 	if (Cmnd->use_sg) {
@@ -1115,15 +1201,18 @@
 		ds = cmd->dataseg;
 		/* fill in first two sg entries: */
 		n = sg_count;
-		if (n > 2)
-			n = 2;
+		if (n > DATASEGS_PER_COMMAND)
+			n = DATASEGS_PER_COMMAND;
+
 		for (i = 0; i < n; i++) {
-			ds[i].d_base_lo = virt_to_bus_low32(sg->address);
-			ds[i].d_base_high = virt_to_bus_high32(sg->address);
+			ds[i].d_base = virt_to_bus_low32(sg->address);
+#if BITS_PER_LONG > 32
+			ds[i].d_base_hi = virt_to_bus_high32(sg->address);
+#endif
 			ds[i].d_count = sg->length;
 			++sg;
 		}
-		sg_count -= 2;
+		sg_count -= DATASEGS_PER_COMMAND;
 
 		while (sg_count > 0) {
 			++cmd->hdr.entry_cnt;
@@ -1132,28 +1221,31 @@
 			memset(cont, 0, sizeof(struct Continuation_Entry));
 			in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
 			if (in_ptr == out_ptr) {
-				DEBUG(printk("isp2100: unexpected request queue overflow\n"));
+				DEBUG(printk("qlogicfc%d : unexpected request queue overflow\n", hostdata->host_id));
 				return 1;
 			}
 			TRACE("queue continuation", in_ptr, 0);
 			cont->hdr.entry_type = ENTRY_CONTINUATION;
 			ds = cont->dataseg;
 			n = sg_count;
-			if (n > 5)
-				n = 5;
+			if (n > DATASEGS_PER_CONT)
+				n = DATASEGS_PER_CONT;
 			for (i = 0; i < n; ++i) {
-				ds[i].d_base_lo = virt_to_bus_low32(sg->address);
-				ds[i].d_base_high = virt_to_bus_high32(sg->address);
+				ds[i].d_base = virt_to_bus_low32(sg->address);
+#if BITS_PER_LONG > 32
+				ds[i].d_base_hi = virt_to_bus_high32(sg->address);
+#endif
 				ds[i].d_count = sg->length;
 				++sg;
 			}
 			sg_count -= n;
 		}
 	} else {
-		cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->request_buffer);
-		cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->request_buffer);
-		cmd->dataseg[0].d_count =
-		    (u_int) Cmnd->request_bufflen;
+		cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer);
+#if BITS_PER_LONG > 32
+		cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+#endif
+		cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen;
 		cmd->segment_cnt = 1;
 	}
 
@@ -1161,12 +1253,15 @@
 	case WRITE_10:
 	case WRITE_6:
 	case WRITE_BUFFER:
+	case MODE_SELECT:
 		cmd->control_flags = CFLAG_WRITE;
 		break;
 	case REQUEST_SENSE:
 		/* scsi.c expects sense info in a different buffer */
-		cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->sense_buffer);
-		cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->sense_buffer);
+		cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer);
+#if BITS_PER_LONG > 32
+		cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+#endif
 		cmd->segment_cnt = 1;
 		cmd->control_flags = CFLAG_READ;
 		break;
@@ -1197,6 +1292,7 @@
 	hostdata->req_in_ptr = in_ptr;
 
 	hostdata->queued++;
+
 	num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
 	num_free = (num_free > 2) ? num_free - 2 : 0;
 	host->can_queue = hostdata->queued + num_free;
@@ -1207,7 +1303,7 @@
 	/* this is really gross */
 	if (host->can_queue <= host->host_busy){
 	        if (host->can_queue+2 < host->host_busy) 
-			DEBUG(printk("qlogicfc.c crosses its fingers.\n"));
+			DEBUG(printk("qlogicfc%d.c crosses its fingers.\n", hostdata->host_id));
 		host->can_queue = host->host_busy + 1;
 	}
 
@@ -1242,11 +1338,11 @@
 
 	hostdata = (struct isp2100_hostdata *) host->hostdata;
 
-	DEBUG_INTR(printk("qlogicfc : interrupt on line %d\n", irq));
+	DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq));
 
 	if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) {
 		/* spurious interrupts can happen legally */
-		DEBUG_INTR(printk("qlogicfc: got spurious interrupt\n"));
+		DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id));
 		return;
 	}
 	in_ptr = inw(host->io_port + MBOX5);
@@ -1255,26 +1351,28 @@
 	if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
 		status = inw(host->io_port + MBOX0);
 
-		DEBUG_INTR(printk("qlogicfc : mbox completion status: %x\n",
-				  status));
+		DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n",
+				  hostdata->host_id, status));
 
 		switch (status) {
 		case LOOP_UP:
-			hostdata->loop_up = 2;
+		        printk("qlogicfc%d : loop is up\n", hostdata->host_id);
+			hostdata->adapter_state = AS_REDO_PORTDB;
 			break;
 		case LOOP_DOWN:
-			hostdata->loop_up = 0;
+		        printk("qlogicfc%d : loop is down\n", hostdata->host_id);
+			hostdata->adapter_state = AS_LOOP_DOWN;
 			break;
 		case LIP_OCCURED:
 		case CHANGE_NOTIFICATION:
 		case PORT_DB_CHANGED:
 		case LIP_RECEIVED:
-			if (hostdata->loop_up == 1)
-				hostdata->loop_up = 2;
+			if (hostdata->adapter_state == AS_LOOP_GOOD)
+				hostdata->adapter_state = AS_REDO_PORTDB;
 			break;
 		case SYSTEM_ERROR:
-			printk("The firmware just choked.\n");
-			hostdata->loop_up = -1;
+			printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id);
+			hostdata->adapter_state = AS_FIRMWARE_DEAD;
 			break;
 		case SCSI_COMMAND_COMPLETE:
 			handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16);
@@ -1286,7 +1384,7 @@
 				Cmnd->result = 0x0;
 				(*Cmnd->scsi_done) (Cmnd);
 			} else
-				printk("qlogicfc.c: got a null value out of handle_ptrs, this sucks\n");
+				printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id);
 			break;
 		case MBOX_COMMAND_COMPLETE:
 		case INVALID_COMMAND:
@@ -1301,12 +1399,12 @@
 			outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
 			return;
 		default:
-			printk("qlogicfc: got an unknown status? %x\n", status);
+			printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status);
 		}
 		outw(0x0, host->io_port + PCI_SEMAPHORE);
 	} else {
-		DEBUG_INTR(printk("qlogicfc : response queue update\n"));
-		DEBUG_INTR(printk("qlogicfc : response queue depth %d\n", RES_QUEUE_DEPTH(in_ptr, out_ptr)));
+		DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id));
+		DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr)));
 
 		while (out_ptr != in_ptr) {
 			sts = (struct Status_Entry *) &hostdata->res[out_ptr][0];
@@ -1314,24 +1412,41 @@
                  
 			TRACE("done", out_ptr, Cmnd);
 			DEBUG_INTR(isp2100_print_status_entry(sts));
-			if (sts->hdr.entry_type == ENTRY_STATUS) {
-				Cmnd = hostdata->handle_ptrs[sts->handle];
+			if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) {
 				Cmnd->result = isp2100_return_status(sts);
 				hostdata->handle_ptrs[sts->handle] = NULL;
 				hostdata->queued--;
-				if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) {
+
+				/* 
+				 * if any of the following are true we do not
+				 * call scsi_done.  if the status is CS_ABORTED
+				 * we dont have to call done because the upper
+				 * level should already know its aborted.
+				 */
+				if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number 
+				    || sts->completion_status == CS_ABORTED){
 					hostdata->handle_serials[sts->handle] = 0;
 					outw(out_ptr, host->io_port + MBOX5);
 					continue;
 				}
-				hostdata->handle_serials[sts->handle] = 0;
+				/*
+				 * if we get back an error indicating the port
+				 * is not there or if the loop is down and 
+				 * this is a device that used to be there 
+				 * allow the command to timeout.
+				 * the device may well be back in a couple of
+				 * seconds.
+				 */
+				if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){
+					outw(out_ptr, host->io_port + MBOX5);
+					continue;
+				}
 			} else {
 				outw(out_ptr, host->io_port + MBOX5);
 				continue;
 			}
 
 			if (sts->completion_status == CS_RESET_OCCURRED
-			    || sts->completion_status == CS_ABORTED
 			    || (sts->status_flags & STF_BUS_RESET))
 				hostdata->send_marker = 1;
 
@@ -1345,7 +1460,7 @@
 			if (Cmnd->scsi_done != NULL) {
 				(*Cmnd->scsi_done) (Cmnd);
 			} else
-				printk("Ouch, scsi done is NULL\n");
+				printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id);
 		}
 		hostdata->res_out_ptr = out_ptr;
 	}
@@ -1363,7 +1478,7 @@
 
 	if (host->can_queue <= host->host_busy){
 	        if (host->can_queue+2 < host->host_busy) 
-		        DEBUG(printk("qlogicfc crosses its fingers.\n"));
+		        DEBUG(printk("qlogicfc%d : crosses its fingers.\n", hostdata->host_id));
 		host->can_queue = host->host_busy + 1;
 	}
 
@@ -1448,7 +1563,7 @@
 	int i;
 	struct Scsi_Host *host;
 	struct isp2100_hostdata *hostdata;
-	int return_status = SCSI_ABORT_SUCCESS;
+	int return_status = SUCCESS;
 
 	ENTER("isp2100_abort");
 
@@ -1459,27 +1574,39 @@
 		if (hostdata->handle_ptrs[i] == Cmnd)
 			break;
 
-	if (i == QLOGICFC_REQ_QUEUE_LEN)
-		return SCSI_ABORT_ERROR;
+	if (i == QLOGICFC_REQ_QUEUE_LEN){
+		return SUCCESS;
+	}
 
 	isp2100_disable_irqs(host);
 
 	param[0] = MBOX_ABORT_IOCB;
+#if ISP2100_PORTDB
+	param[1] = (((u_short) hostdata->port_db[Cmnd->target].loop_id) << 8) | Cmnd->lun;
+#else
 	param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
-	param[2] = i >> 16;
-	param[3] = i & 0xffff;
+#endif
+	param[2] = i & 0xffff;
+	param[3] = i >> 16;
 
 	isp2100_mbox_command(host, param);
 
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc : scsi abort failure: %x\n", param[0]);
+		printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]);
 		if (param[0] == 0x4005)
 			Cmnd->result = DID_ERROR << 16;
 		if (param[0] == 0x4006)
 			Cmnd->result = DID_BAD_TARGET << 16;
-		(*Cmnd->scsi_done) (Cmnd);
-		return_status = SCSI_ABORT_ERROR;
+		return_status = FAILED;
 	}
+
+	if (return_status != SUCCESS){
+		param[0] = MBOX_GET_FIRMWARE_STATE;
+		isp2100_mbox_command(host, param);
+		printk("qlogicfc%d : abort failed\n", hostdata->host_id);
+		printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]);
+	}
+
 	isp2100_enable_irqs(host);
 
 	LEAVE("isp2100_abort");
@@ -1507,7 +1634,7 @@
 	isp2100_mbox_command(host, param);
 
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc : scsi bus reset failure: %x\n", param[0]);
+		printk("qlogicfc%d : scsi bus reset failure: %x\n", hostdata->host_id, param[0]);
 		return_status = SCSI_RESET_ERROR;
 	}
 	isp2100_enable_irqs(host);
@@ -1546,6 +1673,8 @@
 
 	ENTER("isp2100_reset_hardware");
 
+	hostdata = (struct isp2100_hostdata *) host->hostdata;
+
 	outw(0x01, host->io_port + ISP_CTRL_STATUS);
 	outw(HCCR_RESET, host->io_port + HOST_HCCR);
 	outw(HCCR_RELEASE, host->io_port + HOST_HCCR);
@@ -1555,22 +1684,22 @@
 	while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY)
 		barrier();
 	if (!loop_count)
-		printk("qlogicfc: reset_hardware loop timeout\n");
+		printk("qlogicfc%d : reset_hardware loop timeout\n", hostdata->host_id);
 
 
 
 #if DEBUG_ISP2100
-	printk("qlogicfc : mbox 0 0x%04x \n", inw(host->io_port + MBOX0));
-	printk("qlogicfc : mbox 1 0x%04x \n", inw(host->io_port + MBOX1));
-	printk("qlogicfc : mbox 2 0x%04x \n", inw(host->io_port + MBOX2));
-	printk("qlogicfc : mbox 3 0x%04x \n", inw(host->io_port + MBOX3));
-	printk("qlogicfc : mbox 4 0x%04x \n", inw(host->io_port + MBOX4));
-	printk("qlogicfc : mbox 5 0x%04x \n", inw(host->io_port + MBOX5));
-	printk("qlogicfc : mbox 6 0x%04x \n", inw(host->io_port + MBOX6));
-	printk("qlogicfc : mbox 7 0x%04x \n", inw(host->io_port + MBOX7));
+	printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX0));
+	printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX1));
+	printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX2));
+	printk("qlogicfc%d : mbox 3 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX3));
+	printk("qlogicfc%d : mbox 4 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX4));
+	printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX5));
+	printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX6));
+	printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX7));
 #endif				/* DEBUG_ISP2100 */
 
-	DEBUG(printk("qlogicfc : verifying checksum\n"));
+	DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id));
 
 #if RELOAD_FIRMWARE
 	{
@@ -1583,7 +1712,7 @@
 			isp2100_mbox_command(host, param);
 
 			if (param[0] != MBOX_COMMAND_COMPLETE) {
-				printk("qlogicfc : firmware load failure\n");
+				printk("qlogicfc%d : firmware load failure\n", hostdata->host_id);
 				return 1;
 			}
 		}
@@ -1596,10 +1725,10 @@
 	isp2100_mbox_command(host, param);
 
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc : ram checksum failure\n");
+		printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id);
 		return 1;
 	}
-	DEBUG(printk("qlogicfc : executing firmware\n"));
+	DEBUG(printk("qlogicfc%d : executing firmware\n", hostdata->host_id));
 
 	param[0] = MBOX_EXEC_FIRMWARE;
 	param[1] = risc_code_addr01;
@@ -1611,18 +1740,16 @@
 	isp2100_mbox_command(host, param);
 
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc : about firmware failure\n");
+		printk("qlogicfc%d : about firmware failure\n", hostdata->host_id);
 		return 1;
 	}
-	DEBUG(printk("qlogicfc : firmware major revision %d\n", param[1]));
-	DEBUG(printk("qlogicfc : firmware minor revision %d\n", param[2]));
-
-	hostdata = (struct isp2100_hostdata *) host->hostdata;
+	DEBUG(printk("qlogicfc%d : firmware major revision %d\n", hostdata->host_id,  param[1]));
+	DEBUG(printk("qlogicfc%d : firmware minor revision %d\n", hostdata->host_id,  param[2]));
 
 #ifdef USE_NVRAM_DEFAULTS
 
 	if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) {
-		printk("qlogicfc: Could not read from NVRAM\n");
+		printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id);
 	}
 #endif
 
@@ -1644,13 +1771,13 @@
 	param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff);
 	isp2100_mbox_command(host, param);
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc.c: Ouch 0x%04x\n", param[0]);
+		printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id,  param[0]);
 		return 1;
 	}
 	param[0] = MBOX_GET_FIRMWARE_STATE;
 	isp2100_mbox_command(host, param);
 	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicfc.c: 0x%04x\n", param[0]);
+		printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id,  param[0]);
 		return 1;
 	}
 
@@ -1698,7 +1825,7 @@
 
 	if (pci_read_config_word(pdev, PCI_COMMAND, &command)
 	  || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) {
-		printk("qlogicfc : error reading PCI configuration\n");
+		printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id);
 		return 1;
 	}
 	io_base = pdev->base_address[0];
@@ -1707,28 +1834,28 @@
 
 
 	if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
-		printk("qlogicfc : 0x%04x is not QLogic vendor ID\n",
+		printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, 
 		       pdev->vendor);
 		return 1;
 	}
 	if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) {
-		printk("qlogicfc : 0x%04x does not match ISP2100 device id\n",
+		printk("qlogicfc%d : 0x%04x does not match ISP2100 device id\n", hostdata->host_id, 
 		       pdev->device);
 		return 1;
 	}
 	if (command & PCI_COMMAND_IO && (io_base & 3) == 1)
 		io_base &= PCI_BASE_ADDRESS_IO_MASK;
 	else {
-		printk("qlogicfc : i/o mapping is disabled\n");
+		printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id);
 		return 1;
 	}
 
 	if (!(command & PCI_COMMAND_MASTER)) {
-		printk("qlogicfc : bus mastering is disabled\n");
+		printk("qlogicfc%d : bus mastering is disabled\n", hostdata->host_id);
 		return 1;
 	}
 	if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3)
-		printk("qlogicfc : new isp2100 revision ID (%d)\n", revision);
+		printk("qlogicfc%d : new isp2100 revision ID (%d)\n", hostdata->host_id,  revision);
 
 
 	hostdata->revision = revision;
@@ -1800,21 +1927,22 @@
 	int loop_count;
 	struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata;
 
-	if (mbox_param[param[0]] == 0)
+	if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD)
 		return 1;
 
 	loop_count = DEFAULT_LOOP_COUNT;
 	while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080)
 		barrier();
 	if (!loop_count) {
-		printk("qlogicfc: mbox_command loop timeout #1\n");
+		printk("qlogicfc%d : mbox_command loop timeout #1\n", hostdata->host_id);
 		param[0] = 0x4006;
+		hostdata->adapter_state = AS_FIRMWARE_DEAD;
 		return 1;
 	}
 	hostdata->mbox_done = 0;
 
 	if (mbox_param[param[0]] == 0)
-		printk("qlogicfc: invalid mbox command\n");
+		printk("qlogicfc%d : invalid mbox command\n", hostdata->host_id);
 
 	if (mbox_param[param[0]] & 0x80)
 		outw(param[7], host->io_port + MBOX7);
@@ -1843,7 +1971,8 @@
 		}
 
 		if (!loop_count) {
-			printk("qlogicfc: mbox_command loop timeout #2\n");
+			hostdata->adapter_state = AS_FIRMWARE_DEAD;
+			printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id);
 			break;
 		}
 		isp2100_intr_handler(host->irq, host, NULL);
@@ -1858,7 +1987,7 @@
 		barrier();
 	}
 	if (!loop_count)
-		printk("qlogicfc: mbox_command loop timeout #3\n");
+		printk("qlogicfc%d : mbox_command loop timeout #3\n", hostdata->host_id);
 
 	param[7] = inw(host->io_port + MBOX7);
 	param[6] = inw(host->io_port + MBOX6);
@@ -1873,19 +2002,21 @@
 	outw(0x0, host->io_port + PCI_SEMAPHORE);
 
 	if (inw(host->io_port + HOST_HCCR) & 0x0080) {
-		printk("mbox op is still pending\n");
+		hostdata->adapter_state = AS_FIRMWARE_DEAD;
+		printk("qlogicfc%d : mbox op is still pending\n", hostdata->host_id);
 	}
 	return 0;
 }
 
+#if DEBUG_ISP2100_INTR
 
 void isp2100_print_status_entry(struct Status_Entry *status)
 {
-	printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
+	printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", 
 	status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
 	printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n",
 	       status->scsi_status, status->completion_status);
-	printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n",
+	printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", 
 	       status->state_flags, status->status_flags);
 	printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n",
 	       status->res_info_len, status->req_sense_len);
@@ -1893,6 +2024,7 @@
 
 }
 
+#endif                         /* DEBUG_ISP2100_INTR */
 
 
 #if DEBUG_ISP2100
@@ -1901,7 +2033,7 @@
 {
 	int i;
 
-	printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
+	printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
 	       cmd->target, cmd->lun, cmd->cmd_len);
 	printk("qlogicfc : command = ");
 	for (i = 0; i < cmd->cmd_len; i++)
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h
--- v2.3.9/linux/drivers/scsi/qlogicfc.h	Wed Feb 24 16:27:54 1999
+++ linux/drivers/scsi/qlogicfc.h	Mon Jul  5 19:58:24 1999
@@ -61,8 +61,17 @@
  * requests are queued serially and the scatter/gather limit is
  * determined for each queue request anew.
  */
-#define QLOGICFC_REQ_QUEUE_LEN	63	/* must be power of two - 1 */
-#define QLOGICFC_MAX_SG(ql)	(2 + (((ql) > 0) ? 5*((ql) - 1) : 0))
+
+#if BITS_PER_LONG > 32
+#define DATASEGS_PER_COMMAND 2
+#define DATASEGS_PER_CONT 5
+#else
+#define DATASEGS_PER_COMMAND 3
+#define DATASEGS_PER_CONT 7
+#endif
+
+#define QLOGICFC_REQ_QUEUE_LEN	127	/* must be power of two - 1 */
+#define QLOGICFC_MAX_SG(ql)	(DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
 #define QLOGICFC_CMD_PER_LUN    8
 
 int isp2100_detect(Scsi_Host_Template *);
@@ -84,16 +93,16 @@
         release:                isp2100_release,                           \
         info:                   isp2100_info,                              \
         queuecommand:           isp2100_queuecommand,                      \
-        abort:                  isp2100_abort,                             \
+        eh_abort_handler:       isp2100_abort,                             \
         reset:                  isp2100_reset,                             \
         bios_param:             isp2100_biosparam,                         \
         can_queue:              QLOGICFC_REQ_QUEUE_LEN,                    \
         this_id:                -1,                                        \
         sg_tablesize:           QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN),   \
-        cmd_per_lun:            QLOGICFC_CMD_PER_LUN,                      \
+	cmd_per_lun:		QLOGICFC_CMD_PER_LUN, 			   \
         present:                0,                                         \
         unchecked_isa_dma:      0,                                         \
-        use_clustering:         DISABLE_CLUSTERING                         \
+        use_clustering:         ENABLE_CLUSTERING 			   \
 }
 
 #endif /* _QLOGICFC_H */
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.9/linux/drivers/scsi/qlogicisp.c	Thu Apr 22 19:30:08 1999
+++ linux/drivers/scsi/qlogicisp.c	Mon Jul  5 19:58:24 1999
@@ -1065,8 +1065,10 @@
 		ip[0] = 255;
 		ip[1] = 63;
 		ip[2] = size / (ip[0] * ip[1]);
+#if 0
 		if (ip[2] > 1023)
 			ip[2] = 1023;
+#endif			
 	}
 
 	LEAVE("isp1020_biosparam");
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v2.3.9/linux/drivers/scsi/scsi_debug.c	Sat Jan  2 10:23:01 1999
+++ linux/drivers/scsi/scsi_debug.c	Mon Jul  5 20:35:18 1999
@@ -22,10 +22,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#ifdef MODULE
-#include <linux/module.h>
-#endif
-
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.9/linux/drivers/scsi/sd.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/scsi/sd.c	Tue Jul  6 19:08:33 1999
@@ -1050,6 +1050,7 @@
 
     SCpnt->transfersize = rscsi_disks[dev].sector_size;
     SCpnt->underflow = this_count << 9;
+    SCpnt->cmd_len = 0;
     scsi_do_cmd (SCpnt, (void *) cmd, buff,
 		 this_count * rscsi_disks[dev].sector_size,
 		 rw_intr,
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.9/linux/drivers/scsi/st.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/scsi/st.c	Sat Jul  3 10:42:38 1999
@@ -890,7 +890,7 @@
     kdev_t devt = inode->i_rdev;
     int dev;
 
-    if (atomic_read(&filp->f_count) > 1)
+    if (file_count(filp) > 1)
 	return 0;
 
     dev = TAPE_NR(devt);
diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c
--- v2.3.9/linux/drivers/scsi/sym53c416.c	Wed Feb 24 16:28:43 1999
+++ linux/drivers/scsi/sym53c416.c	Mon Jul  5 20:35:18 1999
@@ -3,6 +3,10 @@
  *  Low-level SCSI driver for sym53c416 chip.
  *  Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com)
  * 
+ *  Changes : 
+ * 
+ *  Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking
+ * 
  *  LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
  *
  *  This program is free software; you can redistribute it and/or modify it
@@ -25,11 +29,11 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 #include <linux/blk.h>
 #include <linux/version.h>
 #include "scsi.h"
@@ -371,7 +375,9 @@
     printk("sym53c416: Warning: Reset received\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_RESET << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(int_reg & ILCMD)       /* Illegal Command */
@@ -379,7 +385,9 @@
     printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG));
     current_command->SCp.phase = idle;
     current_command->result = DID_ERROR << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(status_reg & GE)         /* Gross Error */
@@ -387,7 +395,9 @@
     printk("sym53c416: Warning: Gross Error\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_ERROR << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(status_reg & PE)         /* Parity Error */
@@ -395,7 +405,9 @@
     printk("sym53c416: Warning: Parity Error\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_PARITY << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(pio_int_reg & (CE | OUE))
@@ -403,7 +415,9 @@
     printk("sym53c416: Warning: PIO Interrupt Error\n");
     current_command->SCp.phase = idle;
     current_command->result = DID_ERROR << 16;
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   if(int_reg & DIS)           /* Disconnect */
@@ -413,7 +427,10 @@
     else
       current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
     current_command->SCp.phase = idle;
+
+    spin_lock_irqsave(&io_request_lock, flags);
     current_command->scsi_done(current_command);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
     }
   /* Now we handle SCSI phases         */
diff -u --recursive --new-file v2.3.9/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.3.9/linux/drivers/sgi/char/graphics.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/sgi/char/graphics.c	Fri Jul  2 15:15:51 1999
@@ -262,8 +262,7 @@
 	NULL,			/* no special mmap-advise */
 	sgi_graphics_nopage,	/* our magic no-page fault handler */
 	NULL,			/* no special mmap-wppage */
-	NULL,			/* no special mmap-swapout */
-	NULL			/* no special mmap-swapin */
+	NULL			/* no special mmap-swapout */
 };
 	
 int
diff -u --recursive --new-file v2.3.9/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.3.9/linux/drivers/sgi/char/shmiq.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/sgi/char/shmiq.c	Fri Jul  2 15:15:51 1999
@@ -302,8 +302,7 @@
 	NULL,			/* no special mmap-advise */
 	shmiq_nopage,		/* our magic no-page fault handler */
 	NULL,			/* no special mmap-wppage */
-	NULL,			/* no special mmap-swapout */
-	NULL			/* no special mmap-swapin */
+	NULL			/* no special mmap-swapout */
 };
 
 static int
diff -u --recursive --new-file v2.3.9/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c
--- v2.3.9/linux/drivers/sgi/char/usema.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/sgi/char/usema.c	Mon Jul  5 19:44:57 1999
@@ -53,8 +53,8 @@
 	if (newfd < 0)
 		return newfd;
 	
-	current->files->fd [newfd] = usema->filp;
-	atomic_inc(&usema->filp->f_count);
+	get_file(usema->filp);
+	fd_install(newfd, usema->filp);
 	/* Is that it? */
 	printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
 	return newfd;
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.3.9/linux/drivers/sound/cmpci.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/sound/cmpci.c	Mon Jul  5 19:58:24 1999
@@ -2311,9 +2311,7 @@
 		index++;
 		continue;
 
-	err_dev4:
 		unregister_sound_midi(s->dev_midi);
-	err_dev3:
 		unregister_sound_mixer(s->dev_mixer);
 	err_dev2:
 		unregister_sound_dsp(s->dev_audio);
@@ -2328,7 +2326,6 @@
 #ifdef CONFIG_SOUND_CMPCI_MIDI
 		release_region(s->iomidi, CM_EXTENT_MIDI);
 #endif
-	err_region4:
 		release_region(s->iobase, CM_EXTENT_CODEC);
 	err_region5:
 		kfree_s(s, sizeof(struct cm_state));
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.3.9/linux/drivers/sound/dev_table.h	Thu May 13 23:22:48 1999
+++ linux/drivers/sound/dev_table.h	Mon Jul  5 19:58:24 1999
@@ -25,30 +25,18 @@
 #define SNDCARD_DESKPROXL		27	/* Compaq Deskpro XL */
 #define SNDCARD_VIDC			28	/* ARMs VIDC */
 #define SNDCARD_SBPNP			29
-#define SNDCARD_OPL3SA1			38
-#define SNDCARD_OPL3SA1_SB		39
-#define SNDCARD_OPL3SA1_MPU		40
 #define SNDCARD_SOFTOSS			36
 #define SNDCARD_VMIDI			37
+#define SNDCARD_OPL3SA1			38	/* Note: clash in msnd.h */
+#define SNDCARD_OPL3SA1_SB		39
+#define SNDCARD_OPL3SA1_MPU		40
 #define SNDCARD_WAVEFRONT               41
 #define SNDCARD_OPL3SA2                 42
 #define SNDCARD_OPL3SA2_MPU             43
 #define SNDCARD_WAVEARTIST		44
+#define SNDCARD_OPL3SA2_MSS             45	/* Originally missed */
 #define SNDCARD_AD1816                  88
 
-void attach_opl3sa_wss (struct address_info *hw_config);
-int probe_opl3sa_wss (struct address_info *hw_config);
-void attach_opl3sa_sb (struct address_info *hw_config);
-int probe_opl3sa_sb (struct address_info *hw_config);
-void attach_opl3sa_mpu (struct address_info *hw_config);
-int probe_opl3sa_mpu (struct address_info *hw_config);
-void unload_opl3sa_wss(struct address_info *hw_info);
-void unload_opl3sa_sb(struct address_info *hw_info);
-void unload_opl3sa_mpu(struct address_info *hw_info);
-void attach_softsyn_card (struct address_info *hw_config);
-int probe_softsyn (struct address_info *hw_config);
-void unload_softsyn (struct address_info *hw_config);
-
 /*
  *	NOTE! 	NOTE!	NOTE!	NOTE!
  *
@@ -424,6 +412,7 @@
 
 #ifdef CONFIG_SOUND_OPL3SA2
 	{"OPL3SA2", 0, SNDCARD_OPL3SA2,	"OPL3SA2",		attach_opl3sa2, probe_opl3sa2, unload_opl3sa2},
+	{"OPL3SA2MSS", 1, SNDCARD_OPL3SA2_MSS,	"OPL3SA2 MSS",		attach_opl3sa2_mss, probe_opl3sa2_mss, unload_opl3sa2_mss},
 	{"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU,	"OPL3SA2 MIDI",		attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu},
 #endif
 
@@ -587,10 +576,11 @@
 #ifndef CONFIG_OPL3SA2_DMA2
 #define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA
 #endif
+	{SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_CTRL_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
+	{SNDCARD_OPL3SA2_MSS, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
 #ifdef CONFIG_OPL3SA2_MPU_BASE
-	{SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
-	{SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifdef CONFIG_SGALAXY
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.9/linux/drivers/sound/es1370.c	Fri Jun 18 10:45:58 1999
+++ linux/drivers/sound/es1370.c	Mon Jul  5 19:58:24 1999
@@ -2308,9 +2308,9 @@
 };
 
 #ifdef MODULE
-__initfunc(int init_module(void))
+int __init init_module(void)
 #else
-__initfunc(int init_es1370(void))
+int __init init_es1370(void)
 #endif
 {
 	struct es1370_state *s;
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.9/linux/drivers/sound/es1371.c	Fri Jun 18 10:45:58 1999
+++ linux/drivers/sound/es1371.c	Mon Jul  5 19:58:24 1999
@@ -2723,9 +2723,9 @@
 };
 
 #ifdef MODULE
-__initfunc(int init_module(void))
+int __init init_module(void)
 #else
-__initfunc(int init_es1371(void))
+int __init init_es1371(void)
 #endif
 {
 	struct es1371_state *s;
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/lowlevel/awe_compat-fbsd.h linux/drivers/sound/lowlevel/awe_compat-fbsd.h
--- v2.3.9/linux/drivers/sound/lowlevel/awe_compat-fbsd.h	Wed Dec 16 12:52:01 1998
+++ linux/drivers/sound/lowlevel/awe_compat-fbsd.h	Mon Jul  5 20:35:18 1999
@@ -51,7 +51,6 @@
 
 #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.9/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.3.9/linux/drivers/sound/maui.c	Thu Nov  5 09:58:46 1998
+++ linux/drivers/sound/maui.c	Mon Jul  5 19:58:24 1999
@@ -15,9 +15,12 @@
  *					system
  *
  *	Status:
- *		Untested
+ *		Andrew J. Kroll		Tested 06/01/1999 with:
+ *					* OSWF.MOT File Version: 1.15
+ *					* OSWF.MOT File Dated: 09/12/94
+ *					* Older versions will cause problems.
  */
- 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/init.h>
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c
--- v2.3.9/linux/drivers/sound/msnd_pinnacle.c	Tue May 11 23:40:50 1999
+++ linux/drivers/sound/msnd_pinnacle.c	Mon Jul  5 19:58:24 1999
@@ -1165,7 +1165,7 @@
 	return -EIO;
 }
 
-__initfunc(static int probe_multisound(void))
+static int __init probe_multisound(void)
 {
 #ifndef MSND_CLASSIC
 	char *xv, *rev = NULL;
@@ -1305,7 +1305,7 @@
 	return 0;
 }
 
-__initfunc(static int calibrate_adc(WORD srate))
+static int __init calibrate_adc(WORD srate)
 {
 	writew(srate, dev.SMA + SMA_wCalFreqAtoD);
 	if (dev.calibrate_signal == 0)
@@ -1427,7 +1427,7 @@
 	return rv;
 }
 
-__initfunc(static int attach_multisound(void))
+static int __init attach_multisound(void)
 {
 	int err;
 
@@ -1491,7 +1491,7 @@
 
 /* Pinnacle/Fiji Logical Device Configuration */
 
-__initfunc(static int msnd_write_cfg(int cfg, int reg, int value))
+static int __init msnd_write_cfg(int cfg, int reg, int value)
 {
 	outb(reg, cfg);
 	outb(value, cfg + 1);
@@ -1502,7 +1502,7 @@
 	return 0;
 }
 
-__initfunc(static int msnd_write_cfg_io0(int cfg, int num, WORD io))
+static int __init msnd_write_cfg_io0(int cfg, int num, WORD io)
 {
 	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 		return -EIO;
@@ -1513,7 +1513,7 @@
 	return 0;
 }
 
-__initfunc(static int msnd_write_cfg_io1(int cfg, int num, WORD io))
+static int __init msnd_write_cfg_io1(int cfg, int num, WORD io)
 {
 	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 		return -EIO;
@@ -1524,7 +1524,7 @@
 	return 0;
 }
 
-__initfunc(static int msnd_write_cfg_irq(int cfg, int num, WORD irq))
+static int __init msnd_write_cfg_irq(int cfg, int num, WORD irq)
 {
 	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 		return -EIO;
@@ -1535,7 +1535,7 @@
 	return 0;
 }
 
-__initfunc(static int msnd_write_cfg_mem(int cfg, int num, int mem))
+static int __init msnd_write_cfg_mem(int cfg, int num, int mem)
 {
 	WORD wmem;
 
@@ -1553,7 +1553,7 @@
 	return 0;
 }
 
-__initfunc(static int msnd_activate_logical(int cfg, int num))
+static int __init msnd_activate_logical(int cfg, int num)
 {
 	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 		return -EIO;
@@ -1562,7 +1562,7 @@
 	return 0;
 }
 
-__initfunc(static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem))
+static int __init msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)
 {
 	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 		return -EIO;
@@ -1584,7 +1584,7 @@
 	int mem;
 } msnd_pinnacle_cfg_t[4];
 
-__initfunc(static int msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device))
+static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device)
 {
 	int i;
 
@@ -1767,9 +1767,9 @@
 calibrate_signal __initdata =		CONFIG_MSND_CALSIGNAL;
 
 #ifdef MSND_CLASSIC
-__initfunc(int msnd_classic_init(void))
+int __init msnd_classic_init(void)
 #else
-__initfunc(int msnd_pinnacle_init(void))
+int __init msnd_pinnacle_init(void)
 #endif /* MSND_CLASSIC */
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c
--- v2.3.9/linux/drivers/sound/opl3sa2.c	Thu Jan  7 09:24:00 1999
+++ linux/drivers/sound/opl3sa2.c	Mon Jul  5 19:58:24 1999
@@ -467,13 +467,13 @@
 }
 
 
-static int probe_opl3sa2_mss(struct address_info *hw_config)
+int probe_opl3sa2_mss(struct address_info *hw_config)
 {
 	return probe_ms_sound(hw_config);
 }
 
 
-static void attach_opl3sa2_mss(struct address_info *hw_config)
+void attach_opl3sa2_mss(struct address_info *hw_config)
 {
 	char mixer_name[64];
 
@@ -516,7 +516,7 @@
 }
 
 
-static void unload_opl3sa2_mss(struct address_info *hw_config)
+void unload_opl3sa2_mss(struct address_info *hw_config)
 {
 	unload_ms_sound(hw_config);
 }
@@ -592,6 +592,9 @@
 	{
 		/* Generate a pretty name */
 		sprintf(chipset_name, "OPL3-SA%c", tag);
+#if defined(CONFIG_OPL3SA2_MPU_BASE) && !defined(MODULE)
+		sound_getconf(SNDCARD_OPL3SA2_MPU)->always_detect = 1;
+#endif
 		return 1;
 	}
 	return 0;
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c
--- v2.3.9/linux/drivers/sound/sb_ess.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/sound/sb_ess.c	Tue Jul  6 10:11:40 1999
@@ -40,10 +40,10 @@
  *								recording problems for high samplerates. I
  *								fixed this by removing ess_calc_best_speed ()
  *								and just doing what the documentation says. 
- *Javier Achirica(May 15 1999): Major cleanup, MPU IRQ sharing, hardware
- *								volume support, PNP chip configuration,
- *								full duplex in most cards, sample rate fine
- *								tuning.
+ * Andy Sloane  (June 4 1999):  Stole some code from ALSA to fix the playback
+ * andy@guildsoftware.com		speed on ES1869, ES1879, ES1887, and ES1888.
+ * 								1879's were previously ignored by this driver;
+ * 								added (untested) support for those.
  *
  * This files contains ESS chip specifics. It's based on the existing ESS
  * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This
@@ -183,7 +183,6 @@
  * ES1946	yes		This is a PCI chip; not handled by this driver
  */
 
-#include <linux/config.h>
 #include <linux/delay.h>
 
 #include "sound_config.h"
@@ -195,29 +194,22 @@
 #define ESSTYPE_LIKE20	-1		/* Mimic 2.0 behaviour					*/
 #define ESSTYPE_DETECT	0		/* Mimic 2.0 behaviour					*/
 
-int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */
+int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */
 
-#define SUBMDL_ES688	0x00	/* Subtype ES688 for specific handling */
-#define SUBMDL_ES1688	0x08	/* Subtype ES1688 for specific handling */
 #define SUBMDL_ES1788	0x10	/* Subtype ES1788 for specific handling */
 #define SUBMDL_ES1868	0x11	/* Subtype ES1868 for specific handling */
 #define SUBMDL_ES1869	0x12	/* Subtype ES1869 for specific handling */
 #define SUBMDL_ES1878	0x13	/* Subtype ES1878 for specific handling */
-#define SUBMDL_ES1879	0x14	/* Subtype ES1879 for specific handling */
-#define SUBMDL_ES1887	0x15	/* Subtype ES1887 for specific handling */
-#define SUBMDL_ES1888	0x16	/* Subtype ES1888 for specific handling */
-
-	/* Recording mixer, stereo full duplex */
-#define ESSCAP_NEW		0x00000100
-	/* ISA PnP configuration */
-#define ESSCAP_PNP		0x00000200
-	/* Full duplex, 6-bit volume, hardware volume controls */
-#define ESSCAP_ES18		0x00000400
-	/* New interrupt handling system (ESS 1887) */
-#define ESSCAP_IRQ		0x00000800
-
-#define ESSFMT_16		0x00000001
-#define ESSFMT_SIGNED	0x00000004
+#define SUBMDL_ES1879	0x16    /* ES1879 was initially forgotten */
+#define SUBMDL_ES1887	0x14	/* Subtype ES1887 for specific handling */
+#define SUBMDL_ES1888	0x15	/* Subtype ES1888 for specific handling */
+
+#define SB_CAP_ES18XX_RATE 0x100
+
+#define ES1688_CLOCK1 795444 /* 128 - div */
+#define ES1688_CLOCK2 397722 /* 256 - div */
+#define ES18XX_CLOCK1 793800 /* 128 - div */
+#define ES18XX_CLOCK2 768000 /* 256 - div */
 
 #ifdef FKS_LOGGING
 static void ess_show_mixerregs (sb_devc *devc);
@@ -233,6 +225,52 @@
  *																			*
  ****************************************************************************/
 
+struct ess_command {short cmd; short data;};
+
+/*
+ * Commands for initializing Audio 1 for input (record)
+ */
+static struct ess_command ess_i08m[] =		/* input 8 bit mono */
+	{ {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };
+static struct ess_command ess_i16m[] =		/* input 16 bit mono */
+	{ {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };
+static struct ess_command ess_i08s[] =		/* input 8 bit stereo */
+	{ {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };
+static struct ess_command ess_i16s[] =		/* input 16 bit stereo */
+	{ {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };
+
+static struct ess_command *ess_inp_cmds[] =
+	{ ess_i08m, ess_i16m, ess_i08s, ess_i16s };
+
+
+/*
+ * Commands for initializing Audio 1 for output (playback)
+ */
+static struct ess_command ess_o08m[] =		/* output 8 bit mono */
+	{ {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };
+static struct ess_command ess_o16m[] =		/* output 16 bit mono */
+	{ {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };
+static struct ess_command ess_o08s[] =		/* output 8 bit stereo */
+	{ {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };
+static struct ess_command ess_o16s[] =		/* output 16 bit stereo */
+	{ {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };
+
+static struct ess_command *ess_out_cmds[] =
+	{ ess_o08m, ess_o16m, ess_o08s, ess_o16s };
+
+static void ess_exec_commands
+	(sb_devc *devc, struct ess_command *cmdtab[])
+{
+	struct ess_command *cmd;
+
+	cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ];
+
+	while (cmd->cmd != -1) {
+		ess_write (devc, cmd->cmd, cmd->data);
+		cmd++;
+	}
+}
+
 static void ess_change
 	(sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val)
 {
@@ -272,21 +310,53 @@
 	devc->irq_mode = IMODE_INPUT;
 }
 
-static int ess_calc_div (int clock, int *speedp, int *diffp)
+static int ess_calc_div (int clock, int revert, int *speedp, int *diffp)
 {
 	int divider;
 	int speed, diff;
+	int retval;
 
 	speed   = *speedp;
 	divider = (clock + speed / 2) / speed;
-	if (divider > 127) {
-		divider = 127;
-	}
+	retval  = revert - divider;
+	if (retval > revert - 1) {
+		retval  = revert - 1;
+		divider = revert - retval;
+	}
+	/* This line is suggested. Must be wrong I think
+	*speedp = (clock + divider / 2) / divider;
+	So I chose the next one */
+
 	*speedp	= clock / divider;
 	diff	= speed - *speedp;
-	*diffp = diff < 0 ? -diff : diff;
+	if (diff < 0) diff =-diff;
+	*diffp  = diff;
+
+	return retval;
+}
+
+static int ess_calc_best_speed
+	(int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp)
+{
+	int speed1 = *speedp, speed2 = *speedp;
+	int div1, div2;
+	int diff1, diff2;
+	int retval;
+
+	div1 = ess_calc_div (clock1, rev1, &speed1, &diff1);
+	div2 = ess_calc_div (clock2, rev2, &speed2, &diff2);
+
+	if (diff1 < diff2) {
+		*divp   = div1;
+		*speedp = speed1;
+		retval  = 1;
+	} else {
+		*divp   = div2;
+		*speedp = speed2;
+		retval  = 2;
+	}
 
-	return 128 - divider;
+	return retval;
 }
 
 /*
@@ -299,30 +369,24 @@
  */
 static void ess_common_speed (sb_devc *devc, int *speedp, int *divp)
 {
-	int speed1 = *speedp, speed2 = *speedp;
-	int div1, div2;
-	int diff1, diff2;
+	int diff = 0, div;
 
-	if (devc->caps & ESSCAP_NEW) {
-		div1 = 0x000 | ess_calc_div (793800, &speed1, &diff1);
-		div2 = 0x080 | ess_calc_div (768000, &speed2, &diff2);
+	if (devc->duplex) {
+		/*
+		 * The 0x80 is important for the first audio channel
+		 */
+		div = 0x80 | ess_calc_div (795500, 128, speedp, &diff);
+	} else if(devc->caps & SB_CAP_ES18XX_RATE) {
+		ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, 
+						&div, speedp);
 	} else {
 		if (*speedp > 22000) {
-			div1 = 0x080 | ess_calc_div (795444, &speed1, &diff1);
-			div2 = 0x180 | ess_calc_div (793800, &speed2, &diff2);
+			div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff);
 		} else {
-			div1 = 0x000 | ess_calc_div (397722, &speed1, &diff1);
-			div2 = 0x100 | ess_calc_div (396900, &speed2, &diff2);
+			div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff);
 		}
 	}
-
-	if (diff1 < diff2) {
-		*divp   = div1;
-		*speedp = speed1;
-	} else {
-		*divp   = div2;
-		*speedp = speed2;
-	}
+	*divp = div;
 }
 
 static void ess_speed (sb_devc *devc, int audionum)
@@ -341,13 +405,21 @@
 
 	div2 = 256 - 7160000 / (speed * 82);
 
-	if ((devc->caps & ESSCAP_NEW) && audionum != 1) {
-		ess_setmixer (devc, 0x70, div);
-		ess_setmixer (devc, 0x72, div2);
+	if (!devc->duplex) audionum = 1;
+
+	if (audionum == 1) {
+		/* Change behaviour of register A1 *
+		sb_chg_mixer(devc, 0x71, 0x20, 0x20)
+		* For ES1869 only??? */
+		ess_write (devc, 0xa1, div);
+		ess_write (devc, 0xa2, div2);
 	} else {
-		ess_change (devc, 0xba, 0x40, (div & 0x100) ? 0x40 : 0x00);
-		ess_write (devc, 0xa1, div & 0xff);
+		ess_setmixer (devc, 0x70, div);
+		/*
+		 * FKS: fascinating: 0x72 doesn't seem to work.
+		 */
 		ess_write (devc, 0xa2, div2);
+		ess_setmixer (devc, 0x72, div2);
 	}
 }
 
@@ -355,14 +427,77 @@
 {
 	sb_devc *devc = audio_devs[dev]->devc;
 
+	ess_speed(devc, 1);
+
+	sb_dsp_command(devc, DSP_CMD_SPKOFF);
+
 	ess_write (devc, 0xb8, 0x0e);	/* Auto init DMA mode */
-	ess_change (devc, 0xa8, 0x0b, 3 - devc->channels);	/* Mono/stereo */
+	ess_change (devc, 0xa8, 0x03, 3 - devc->channels);	/* Mono/stereo */
+	ess_write (devc, 0xb9, 2);	/* Demand mode (4 bytes/DMA request) */
 
+	ess_exec_commands (devc, ess_inp_cmds);
+
+	ess_change (devc, 0xb1, 0xf0, 0x50);
+	ess_change (devc, 0xb2, 0xf0, 0x50);
+
+	devc->trigger_bits = 0;
+	return 0;
+}
+
+static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount)
+{
+	sb_devc *devc = audio_devs[dev]->devc;
+
+	sb_dsp_reset(devc);
 	ess_speed(devc, 1);
+	ess_write (devc, 0xb8, 4);	/* Auto init DMA mode */
+	ess_change (devc, 0xa8, 0x03, 3 - devc->channels);	/* Mono/stereo */
+	ess_write (devc, 0xb9, 2);	/* Demand mode (4 bytes/request) */
 
-    ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51);
-    ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) |
-		((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40));
+	ess_exec_commands (devc, ess_out_cmds);
+
+	ess_change (devc, 0xb1, 0xf0, 0x50);	/* Enable DMA */
+	ess_change (devc, 0xb2, 0xf0, 0x50);	/* Enable IRQ */
+
+	sb_dsp_command(devc, DSP_CMD_SPKON);	/* There be sound! */
+
+	devc->trigger_bits = 0;
+	return 0;
+}
+
+static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount)
+{
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned char bits;
+
+/* FKS: qqq
+	sb_dsp_reset(devc);
+*/
+
+	/*
+	 * Auto-Initialize:
+	 * DMA mode + demand mode (8 bytes/request, yes I want it all!)
+	 * But leave 16-bit DMA bit untouched!
+	 */
+	ess_chgmixer (devc, 0x78, 0xd0, 0xd0);
+
+	ess_speed(devc, 2);
+
+	/* bits 4:3 on ES1887 represent recording source. Keep them! */
+	bits = ess_getmixer (devc, 0x7a) & 0x18;
+
+	/* Set stereo/mono */
+	if (devc->channels != 1) bits |= 0x02;
+
+	/* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */
+	if (devc->bits != AFMT_U8) bits |= 0x05;	/* 16 bit */
+
+	/* Enable DMA, IRQ will be shared (hopefully)*/
+	bits |= 0x60;
+
+	ess_setmixer (devc, 0x7a, bits);
+
+	ess_mixer_reload (devc, SOUND_MIXER_PCM);	/* There be sound! */
 
 	devc->trigger_bits = 0;
 	return 0;
@@ -378,79 +513,144 @@
 #endif
 
 	if (devc->duplex) {
-		ess_speed(devc, 2);
+		return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount);
+	} else {
+		return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount);
+	}
+}
 
-	    ess_chgmixer (devc, 0x7a, 0x07, ((devc->bits & ESSFMT_SIGNED) ? 4 : 0) |
-			((devc->bits & ESSFMT_16) ? 1 : 0) | ((devc->channels > 1) ? 2 : 0));
+static void ess_audio_halt_xfer(int dev)
+{
+	unsigned long flags;
+	sb_devc *devc = audio_devs[dev]->devc;
 
-		if (devc->caps & ESSCAP_NEW)
-			ess_mixer_reload (devc, SOUND_MIXER_PCM);	/* There be sound! */
-		else
-			sb_dsp_command(devc, DSP_CMD_SPKON);	/* There be sound! */
-	} else {
-		ess_write (devc, 0xb8, 4);	/* Auto init DMA mode */
-		ess_change (devc, 0xa8, 0x03, 3 - devc->channels);	/* Mono/stereo */
+	save_flags(flags);
+	cli();
+	sb_dsp_reset(devc);
+	restore_flags(flags);
 
-		ess_speed(devc, 1);
+	/*
+	 * Audio 2 may still be operational! Creates awful sounds!
+	 */
+	if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00);
+}
 
-	    ess_write (devc, 0xb6, (devc->bits & ESSFMT_SIGNED) ? 0 : 0x80);
-	    ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51);
-	    ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) |
-			((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40));
+static void ess_audio_start_input
+	(int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
+	short c = -nr_bytes;
 
-		sb_dsp_command(devc, DSP_CMD_SPKON);	/* There be sound! */
-	}
-	devc->trigger_bits = 0;
-	return 0;
+	/*
+	 * Start a DMA input to the buffer pointed by dmaqtail
+	 */
+
+	if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1;
+	count--;
+
+	devc->irq_mode = IMODE_INPUT;
+
+	ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+	ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+	ess_change (devc, 0xb8, 0x0f, 0x0f);	/* Go */
+	devc->intr_active = 1;
 }
 
-static void ess_audio_halt_xfer(int dev)
+static void ess_audio_output_block_audio1
+	(int dev, unsigned long buf, int nr_bytes, int intrflag)
 {
+	int count = nr_bytes;
 	sb_devc *devc = audio_devs[dev]->devc;
+	short c = -nr_bytes;
 
-	sb_dsp_command (devc, DSP_CMD_SPKOFF);
+	if (audio_devs[dev]->dmap_out->dma > 3)
+		count >>= 1;
+	count--;
 
-	if (devc->caps & ESSCAP_NEW) {
-		ess_setmixer (devc, 0x7c, 0);
-	}
+	devc->irq_mode = IMODE_OUTPUT;
 
-	ess_change (devc, 0xb8, 0x0f, 0x00);	/* Stop */
+	ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+	ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
 
-	if (devc->duplex) {			/* Audio 2 may still be operational! */
-		ess_chgmixer (devc, 0x78, 0x03, 0x00);
+	ess_change (devc, 0xb8, 0x05, 0x05);	/* Go */
+	devc->intr_active = 1;
+}
+
+static void ess_audio_output_block_audio2
+	(int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
+	short c = -nr_bytes;
+
+	if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1;
+	count--;
+
+	ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff));
+	ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+	ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
+
+	devc->irq_mode_16 = IMODE_OUTPUT;
+		devc->intr_active_16 = 1;
+}
+
+static void ess_audio_output_block
+	(int dev, unsigned long buf, int nr_bytes, int intrflag)
+{
+	sb_devc *devc = audio_devs[dev]->devc;
+
+	if (devc->duplex) {
+		ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag);
+	} else {
+		ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag);
 	}
 }
 
+/*
+ * FKS: the if-statements for both bits and bits_16 are quite alike.
+ * Combine this...
+ */
 static void ess_audio_trigger(int dev, int bits)
 {
 	sb_devc *devc = audio_devs[dev]->devc;
 
-	int bits_16 = bits & devc->irq_mode_16 & IMODE_OUTPUT;
+	int bits_16 = bits & devc->irq_mode_16;
 	bits &= devc->irq_mode;
 
 	if (!bits && !bits_16) {
-		sb_dsp_command (devc, 0xd0);			/* Halt DMA */
-		ess_chgmixer (devc, 0x78, 0x04, 0x00);	/* Halt DMA 2 */
+		/* FKS oh oh.... wrong?? for dma 16? */
+		sb_dsp_command(devc, 0xd0);	/* Halt DMA */
 	}
 
 	if (bits) {
-		short c = -devc->trg_bytes;
-
-		ess_write (devc, 0xa4, (unsigned char)((unsigned short) c & 0xff));
-		ess_write (devc, 0xa5, (unsigned char)((unsigned short) c >> 8));
-		ess_change (devc, 0xb8, 0x0f, (devc->irq_mode==IMODE_INPUT)?0x0f:0x05);
+		switch (devc->irq_mode)
+		{
+			case IMODE_INPUT:
+				ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+					devc->trg_intrflag);
+				break;
 
-		devc->intr_active = 1;
+			case IMODE_OUTPUT:
+				ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+					devc->trg_intrflag);
+				break;
+		}
 	}
 
 	if (bits_16) {
-		short c = -devc->trg_bytes_16;
-
-		ess_setmixer (devc, 0x74, (unsigned char)((unsigned short) c & 0xff));
-		ess_setmixer (devc, 0x76, (unsigned char)((unsigned short) c >> 8));
-		ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
+		switch (devc->irq_mode_16) {
+		case IMODE_INPUT:
+			ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16,
+					devc->trg_intrflag_16);
+			break;
 
-		devc->intr_active_16 = 1;
+		case IMODE_OUTPUT:
+			ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16,
+					devc->trg_intrflag_16);
+			break;
+		}
 	}
 
 	devc->trigger_bits = bits | bits_16;
@@ -462,8 +662,8 @@
 	int minspeed, maxspeed, dummydiv;
 
 	if (speed > 0) {
-		minspeed = (devc->caps & ESSCAP_NEW) ? 6047  : 3125;
-		maxspeed = 48000;
+		minspeed = (devc->duplex ? 6215  : 5000 );
+		maxspeed = (devc->duplex ? 44100 : 48000);
 		if (speed < minspeed) speed = minspeed;
 		if (speed > maxspeed) speed = maxspeed;
 
@@ -474,46 +674,38 @@
 	return devc->speed;
 }
 
+/*
+ * FKS: This is a one-on-one copy of sb1_audio_set_bits
+ */
 static unsigned int ess_audio_set_bits(int dev, unsigned int bits)
 {
 	sb_devc *devc = audio_devs[dev]->devc;
 
-	switch (bits) {
-		case 0:
-			break;
-		case AFMT_S16_LE:
-			devc->bits = ESSFMT_16 | ESSFMT_SIGNED;
-			break;
-		case AFMT_U16_LE:
-			devc->bits = ESSFMT_16;
-			break;
-		case AFMT_S8:
-			devc->bits = ESSFMT_SIGNED;
-			break;
-		default:
-			devc->bits = 0;
-			break;
+	if (bits != 0) {
+		if (bits == AFMT_U8 || bits == AFMT_S16_LE) {
+			devc->bits = bits;
+		} else {
+			devc->bits = AFMT_U8;
+		}
 	}
 
 	return devc->bits;
 }
 
+/*
+ * FKS: This is a one-on-one copy of sbpro_audio_set_channels
+ * (*) Modified it!!
+ */
 static short ess_audio_set_channels(int dev, short channels)
 {
 	sb_devc *devc = audio_devs[dev]->devc;
 
-	if (devc->fullduplex && !(devc->caps & ESSCAP_NEW)) {
-		devc->channels = 1;
-	} else {
-		if (channels == 1 || channels == 2) {
-			devc->channels = channels;
-		}
-	}
+	if (channels == 1 || channels == 2) devc->channels = channels;
 
 	return devc->channels;
 }
 
-static struct audio_driver ess_audio_driver =   /* ESS ES688/1688/18xx */
+static struct audio_driver ess_audio_driver =   /* ESS ES688/1688 */
 {
 	sb_audio_open,
 	sb_audio_close,
@@ -540,7 +732,7 @@
 		(sb_devc *devc, int *audio_flags, int *format_mask)
 {
 	*audio_flags = DMA_AUTOMODE;
-	*format_mask |= AFMT_S16_LE | AFMT_U16_LE | AFMT_S8;
+	*format_mask |= AFMT_S16_LE;
 
 	if (devc->duplex) {
 		int tmp_dma;
@@ -563,8 +755,10 @@
  *								ESS common									*
  *																			*
  ****************************************************************************/
-static void ess_handle_channel (int dev, int irq_mode)
+static void ess_handle_channel
+	(char *channel, int dev, int intr_active, unsigned char flag, int irq_mode)
 {
+	if (!intr_active || !flag) return;
 #ifdef FKS_REG_LOGGING
 printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
 #endif
@@ -586,77 +780,48 @@
 }
 
 /*
- * In the ESS 1888 model, how do we found out if the MPU interrupted ???
+ * FKS: TODO!!! Finish this!
+ *
+ * I think midi stuff uses uart401, without interrupts.
+ * So IMODE_MIDI isn't a value for devc->irq_mode.
  */
 void ess_intr (sb_devc *devc)
 {
 	int				status;
 	unsigned char	src;
 
-	if (devc->caps & ESSCAP_PNP) {
-		outb (devc->pcibase + 7, 0);		/* Mask IRQs */
-		src = inb (devc->pcibase + 6) & 0x0f;
-	} else if (devc->caps & ESSCAP_IRQ) {
+	if (devc->submodel == SUBMDL_ES1887) {
 		src = ess_getmixer (devc, 0x7f) >> 4;
 	} else {
-		src = inb (DSP_STATUS) & 0x01;
-		if (devc->duplex && (ess_getmixer (devc, 0x7a) & 0x80)) {
-			src |= 0x02;
-		}
-		if ((devc->caps & ESSCAP_ES18) && (ess_getmixer (devc, 0x64) & 0x10)) {
-			src |= 0x04;
-		}
-#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401)
-		/*
-		 * This should work if dev_conf wasn't local to mpu401.c
-		 */
-#if 0
-		if ((int)devc->midi_irq_cookie >= 0 &&
-			!(inb(dev_conf[(int)devc->midi_irq_cookie].base + 1) & 0x80)) {
-			src |= 0x08;
-		}
-#endif
-#endif
+		src = 0xff;
 	}
 
 #ifdef FKS_REG_LOGGING
 printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src);
 #endif
-	if (src & 0x01) {
-		status = inb(DSP_DATA_AVAIL);	/* Acknowledge interrupt */
-		if (devc->intr_active)
-			ess_handle_channel (devc->dev, devc->irq_mode   );
-	}
-
-	if (src & 0x02) {
-		ess_chgmixer (devc, 0x7a, 0x80, 0x00);	/* Acknowledge interrupt */
-		if (devc->intr_active_16)
-			ess_handle_channel (devc->dev, devc->irq_mode_16);
+	ess_handle_channel
+		( "Audio 1"
+		, devc->dev, devc->intr_active   , src & 0x01, devc->irq_mode   );
+	ess_handle_channel
+		( "Audio 2"
+		, devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16);
+	/*
+	 * Acknowledge interrupts
+	 */
+	if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) {
+		ess_chgmixer (devc, 0x7a, 0x80, 0x00);
 	}
 
-	if (src & 0x04) {
-		int left, right;
-
-		ess_setmixer (devc, 0x66, 0x00);	/* Hardware volume IRQ ack */
-
-		left = ess_getmixer (devc, 0x60);
-		right = ess_getmixer (devc, 0x62);
-
-		left = (left & 0x40) ? 0 : ((left * 100 + 31)/ 63);	/* Mute or scale */
-		right = (right & 0x40) ? 0 : ((right * 100 + 31)/ 63);
-
-		devc->levels[SOUND_MIXER_VOLUME] = left | (right << 8);
+	if (src & 0x01) {
+		status = inb(DSP_DATA_AVAIL);
 	}
+}
 
-#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401)
-	if ((int)devc->midi_irq_cookie >= 0 && (src & 0x08)) {
-		mpuintr (devc->irq, devc->midi_irq_cookie, NULL);
-	}
-#endif
+static void ess_extended (sb_devc * devc)
+{
+	/* Enable extended mode */
 
-	if (devc->caps & ESSCAP_PNP) {
-		outb (devc->pcibase + 7, 0xff);		/* Unmask IRQs */
-	}
+	sb_dsp_command(devc, 0xc6);
 }
 
 static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data)
@@ -686,7 +851,7 @@
 
 int ess_dsp_reset(sb_devc * devc)
 {
-	int loopc, val;
+	int loopc;
 
 #ifdef FKS_REG_LOGGING
 printk(KERN_INFO "FKS: ess_dsp_reset 1\n");
@@ -707,102 +872,79 @@
 		DDB(printk("sb: No response to RESET\n"));
 		return 0;   /* Sorry */
 	}
+	ess_extended (devc);
 
-	sb_dsp_command(devc, 0xc6);			/* Enable extended mode */
-	if (!(devc->caps & ESSCAP_PNP)) {
-		ess_setmixer (devc, 0x40, 0x03);	/* Enable joystick and OPL3 */
-
-		switch (devc->irq) {
-			case 2:
-			case 9:
-				val = 1;
-				break;
-			case 5:
-				val = 2;
-				break;
-			case 7:
-				val = 3;
-				break;
-			case 10:
-				val = 4;
-				break;
-			case 11:
-				val = 5;
-				break;
-			default:
-				val = 0;
-		}						/* IRQ config */
-		ess_write (devc, 0xb1, 0xf0 | ((val && val != 5) ? val - 1 : 0));
+	DEB(printk("sb_dsp_reset() OK\n"));
 
-		if (devc->caps & ESSCAP_IRQ) {
-			ess_setmixer (devc, 0x7f, 0x01 | (val << 1)); /* IRQ config */
-		}
+#ifdef FKS_LOGGING
+printk(KERN_INFO "FKS: dsp_reset 2\n");
+ess_show_mixerregs (devc);
+#endif
 
-		switch ((devc->duplex) ? devc->dma16 : devc->dma8) {
-			case 0:
-				val = 0x54;
-				break;
-			case 1:
-				val = 0x58;
-				break;
-			case 3:
-				val = 0x5c;
-				break;
-			default:
-				val = 0;
-		}
-		ess_write (devc, 0xb2, val); /* DMA1 config */
+	return 1;
+}
 
-		if (devc->duplex) {
-			switch (devc->dma8) {
-				case 0:
-					val = 0x04;
-					break;
-				case 1:
-					val = 0x05;
-					break;
-				case 3:
-					val = 0x06;
-					break;
-				case 5:
-					val = 0x07;
-					break;
-				default:
-					val = 0;
-			}
-			ess_write (devc, 0x7d, val); /* DMA2 config */
-		}
-	}
-	ess_change (devc, 0xb1, 0xf0, 0x50);	/* Enable IRQ 1 */
-	ess_change (devc, 0xb2, 0xf0, 0x50);	/* Enable DMA 1 */
-	ess_write (devc, 0xb9, 2);			/* Demand mode (4 bytes/DMA request) */
-	ess_setmixer (devc, 0x7a, 0x40);	/* Enable IRQ 2 */
-			/* Auto-Initialize DMA mode + demand mode (8 bytes/request) */
-	if (devc->caps & ESSCAP_PNP) {
-		ess_setmixer (devc, 0x78, 0xd0);
-		ess_setmixer (devc, 0x64, 0x82);		/* Enable HW volume interrupt */
-	} else {
-		ess_setmixer (devc, 0x78, (devc->dma8 > 4) ? 0xf0 : 0xd0);
-		ess_setmixer (devc, 0x64, 0x42);		/* Enable HW volume interrupt */
-	}
+static int ess_irq_bits (int irq)
+{
+	switch (irq) {
+	case 2:
+	case 9:
+		return 0;
 
-    if (devc->caps & ESSCAP_NEW) {
-		ess_setmixer (devc, 0x71, 0x32); /* Change behaviour of register A1 */
-		ess_setmixer (devc, 0x1c, 0x05); /* Recording source is mixer */
-	} else {
-		ess_change (devc, 0xb7, 0x80, 0x80); /* Enable DMA FIFO */
+	case 5:
+		return 1;
+
+	case 7:
+		return 2;
+
+	case 10:
+		return 3;
+
+	default:
+		printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq);
+		return -1;
 	}
+}
 
-	DEB(printk("sb_dsp_reset() OK\n"));
+/*
+ *	Set IRQ configuration register for all ESS models
+ */
+static int ess_common_set_irq_hw (sb_devc * devc)
+{
+	int irq_bits;
 
-#ifdef FKS_LOGGING
-printk(KERN_INFO "FKS: dsp_reset 2\n");
-ess_show_mixerregs (devc);
-#endif
+	if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return 0;
 
+	if (!ess_write (devc, 0xb1, 0x50 | (irq_bits << 2))) {
+		printk(KERN_ERR "ES1688: Failed to write to IRQ config register\n");
+		return 0;
+	}
 	return 1;
 }
 
+/*
+ * I wanna use modern ES1887 mixer irq handling. Funny is the
+ * fact that my BIOS wants the same. But suppose someone's BIOS
+ * doesn't do this!
+ * This is independent of duplex. If there's a 1887 this will
+ * prevent it from going into 1888 mode.
+ */
+static void ess_es1887_set_irq_hw (sb_devc * devc)
+{
+	int irq_bits;
+
+	if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return;
+
+	ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1));
+}
+
+static int ess_set_irq_hw (sb_devc * devc)
+{
+	if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc);
+
+	return ess_common_set_irq_hw (devc);
+}
+
 #ifdef FKS_TEST
 
 /*
@@ -826,7 +968,7 @@
 };
 #endif
 
-static unsigned int ess_identify (sb_devc * devc, int *control)
+static unsigned int ess_identify (sb_devc * devc)
 {
 	unsigned int val;
 	unsigned long flags;
@@ -840,15 +982,8 @@
 	udelay(20);
 	val |= inb(MIXER_DATA);
 	udelay(20);
-	*control  = inb(MIXER_DATA) << 8;
-	udelay(20);
-	*control |= inb(MIXER_DATA);
-	udelay(20);
 	restore_flags(flags);
 
-	if (*control < 0 || *control > 0x3ff || check_region (*control, 8))
-		*control = 0;
-
 	return val;
 }
 
@@ -875,6 +1010,7 @@
 
 int ess_init(sb_devc * devc, struct address_info *hw_config)
 {
+	unsigned char cfg;
 	int ess_major = 0, ess_minor = 0;
 	int i;
 	static char name[100], modelname[10];
@@ -882,7 +1018,6 @@
 	/*
 	 * Try to detect ESS chips.
 	 */
-	devc->pcibase = 0;
 
 	sb_dsp_command(devc, 0xe7); /* Return identification */
 
@@ -934,10 +1069,10 @@
 		case ESSTYPE_LIKE20:
 			break;
 		case 688:
-			submodel = SUBMDL_ES688;
+			submodel = 0x00;
 			break;
 		case 1688:
-			submodel = SUBMDL_ES1688;
+			submodel = 0x08;
 			break;
 		case 1868:
 			submodel = SUBMDL_ES1868;
@@ -986,7 +1121,7 @@
 		if (chip == NULL) {
 			int type;
 
-			type = ess_identify (devc, &devc->pcibase);
+			type = ess_identify (devc);
 
 			switch (type) {
 			case 0x1868:
@@ -1063,72 +1198,139 @@
 		strcpy(name, "Jazz16");
 	}
 
-	switch (devc->submodel) {
-	case SUBMDL_ES1869:
-	case SUBMDL_ES1879:
-		devc->caps |= ESSCAP_NEW;
-	case SUBMDL_ES1868:
-	case SUBMDL_ES1878:
-		devc->caps |= ESSCAP_PNP | ESSCAP_ES18;
-		break;
-	case SUBMDL_ES1887:
-		devc->caps |= ESSCAP_IRQ;
-	case SUBMDL_ES1888:
-		devc->caps |= ESSCAP_NEW | ESSCAP_ES18;
-	}
-    if (devc->caps & ESSCAP_PNP) {
-		if (!devc->pcibase) {
-			printk (KERN_ERR "ESS PnP chip without PnP registers. Ignored\n");
-			return 0;
-		}
-		request_region (devc->pcibase, 8, "ESS18xx ctrl");
+	/* AAS: info stolen from ALSA: these boards have different clocks */
+	switch(devc->submodel) {
+		case SUBMDL_ES1869:
+		case SUBMDL_ES1887:
+		case SUBMDL_ES1888:
+			devc->caps |= SB_CAP_ES18XX_RATE;
+			break;
+	}
+
+	hw_config->name = name;
+	/* FKS: sb_dsp_reset to enable extended mode???? */
+	sb_dsp_reset(devc); /* Turn on extended mode */
 
-		outb (0x07, devc->pcibase);		/* Selects logical device #1 */
-		outb (0x01, devc->pcibase + 1);
-		outb (0x28, devc->pcibase);
-		i = inb (devc->pcibase + 1) & 0x0f;
-		outb (0x28, devc->pcibase);		/* Sets HW volume IRQ */
-		outb (devc->irq << 4 | i, devc->pcibase + 1);
-		outb (0x70, devc->pcibase);		/* Sets IRQ 1 */
-		outb (devc->irq, devc->pcibase + 1);
-		outb (0x72, devc->pcibase);		/* Sets IRQ 2 */
-		outb (devc->irq, devc->pcibase + 1);
-		outb (0x74, devc->pcibase);		/* Sets DMA 1 */
-		outb (hw_config->dma, devc->pcibase + 1);
-		outb (0x75, devc->pcibase);		/* Sets DMA 2 */
-		outb (hw_config->dma2 >= 0 ? hw_config->dma2 : 4, devc->pcibase + 1);
-	} else if (devc->pcibase) {
-		printk (KERN_INFO "Non-PnP ESS card with PnP registers at %04Xh, ignoring them.\n", devc->pcibase);
-		devc->pcibase = 0;
+	/*
+	 *  Enable joystick and OPL3
+	 */
+	cfg = ess_getmixer (devc, 0x40);
+	ess_setmixer (devc, 0x40, cfg | 0x03);
+	if (devc->submodel >= 8) {		/* ES1688 */
+		devc->caps |= SB_NO_MIDI;   /* ES1688 uses MPU401 MIDI mode */
 	}
+	sb_dsp_reset (devc);
 
-	devc->caps |= SB_NO_MIDI;   /* ES1688 uses MPU401 MIDI mode */
+	/*
+	 * This is important! If it's not done, the IRQ probe in sb_dsp_init
+	 * may fail.
+	 */
+	return ess_set_irq_hw (devc);
+}
 
-	hw_config->name = name;
+static int ess_set_dma_hw(sb_devc * devc)
+{
+	unsigned char cfg, dma_bits = 0, dma16_bits;
+	int dma;
 
-	sb_dsp_reset(devc); /* Turn on extended mode */
+#ifdef FKS_LOGGING
+printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n"
+, devc->dma8, devc->dma16, devc->duplex);
+#endif
 
-	ess_setmixer (devc, 0x00, 0x00);	/* Reset mixer registers */
+	/*
+	 * FKS: It seems as if this duplex flag isn't set yet. Check it.
+	 */
+	dma = devc->dma8;
 
+	if (dma > 3 || dma < 0 || dma == 2) {
+		dma_bits = 0;
+		printk(KERN_ERR "ESS1688: Invalid DMA8 %d\n", dma);
+		return 0;
+	} else {
+		/* Extended mode DMA enable */
+		cfg = 0x50;
+
+		if (dma == 3) {
+			dma_bits = 3;
+		} else {
+			dma_bits = dma + 1;
+		}
+	}
+
+	if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) {
+		printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n");
+		return 0;
+	}
+
+	if (devc->duplex) {
+		dma = devc->dma16;
+		dma16_bits = 0;
+
+		if (dma >= 0) {
+			switch (dma) {
+			case 0:
+				dma_bits = 0x04;
+				break;
+			case 1:
+				dma_bits = 0x05;
+				break;
+			case 3:
+				dma_bits = 0x06;
+				break;
+			case 5:
+				dma_bits   = 0x07;
+				dma16_bits = 0x20;
+				break;
+			default:
+				printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma);
+				return 0;
+			};
+			ess_chgmixer (devc, 0x78, 0x20, dma16_bits);
+			ess_chgmixer (devc, 0x7d, 0x07, dma_bits);
+		}
+	}
 	return 1;
 }
 
 /*
  * This one is called from sb_dsp_init.
+ *
+ * Return values:
+ *  0: Failed
+ *  1: Succeeded or doesn't apply (not SUBMDL_ES1887)
  */
 int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
 {
 	/*
+	 * This for ES1887 to run Full Duplex. Actually ES1888
+	 * is allowed to do so too. I have no idea yet if this
+	 * will work for ES1888 however.
+	 *
 	 * For SB16 having both dma8 and dma16 means enable
-	 * Full Duplex. Let's try this too
+	 * Full Duplex. Let's try this for ES1887 too
+	 *
 	 */
-	if ((devc->caps & ESSCAP_ES18) && hw_config->dma2 >= 0) {
-		devc->dma16 = hw_config->dma2;
-		if (devc->dma8 != devc->dma16) {
+	if (devc->submodel == SUBMDL_ES1887) {
+		if (hw_config->dma2 != -1) {
+			devc->dma16 = hw_config->dma2;
+		}
+		/*
+		 * devc->duplex initialization is put here, cause
+		 * ess_set_dma_hw needs it.
+		 */
+		if (devc->dma8 != devc->dma16 && devc->dma16 != -1) {
 			devc->duplex = 1;
 		}
+
+		if (!ess_set_dma_hw (devc)) {
+			free_irq(devc->irq, devc);
+			return 0;
+		}
+		return 1;
+	} else {
+		return -1;
 	}
-	return 1;
 }
 
 /****************************************************************************
@@ -1149,13 +1351,13 @@
 #define ES1688_MIXER_DEVICES		\
 			( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV	)
 
-#define ES_NEW_RECORDING_DEVICES	\
+#define ES1887_RECORDING_DEVICES	\
 			( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH)
-#define ES_NEW_MIXER_DEVICES		\
+#define ES1887_MIXER_DEVICES		\
 			( ES1688_MIXER_DEVICES											)
 
 /*
- * Mixer registers of ES18xx with new capabilities
+ * Mixer registers of ES1887
  *
  * These registers specifically take care of recording levels. To make the
  * mapping from playback devices to recording devices every recording
@@ -1285,11 +1487,11 @@
 };
 
 /*
- * This one is for new ES's. It's little different from es_rec_mix: it
- * has 0x7c for PCM playback level. This is because uses
+ * This one is for ES1887. It's little different from es_rec_mix: it
+ * has 0x7c for PCM playback level. This is because ES1887 uses
  * Audio 2 for playback.
  */
-static mixer_tab es_new_mix = {
+static mixer_tab es1887_mix = {
 MIX_ENT(SOUND_MIXER_VOLUME,			0x60, 5, 6, 0x62, 5, 6),
 MIX_ENT(SOUND_MIXER_BASS,			0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_TREBLE,			0x00, 0, 0, 0x00, 0, 0),
@@ -1323,6 +1525,16 @@
 MIX_ENT(ES_REC_MIXER_RECLINE3,		0x00, 0, 0, 0x00, 0, 0)
 };
 
+static int ess_has_rec_mixer (int submodel)
+{
+	switch (submodel) {
+	case SUBMDL_ES1887:
+		return 1;
+	default:
+		return 0;
+	};
+};
+
 #ifdef FKS_LOGGING
 static int ess_mixer_mon_regs[]
 	= { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f
@@ -1353,13 +1565,15 @@
 
 	save_flags(flags);
 	cli();
+	if (port >= 0xa0) {
+		ess_write (devc, port, value);
+	} else {
+		outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
 
-	outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
-	udelay(20);
-	outb(((unsigned char) (value & 0xff)), MIXER_DATA);
-	udelay(20);
-
+		udelay(20);
+		outb(((unsigned char) (value & 0xff)), MIXER_DATA);
+		udelay(20);
+	};
 	restore_flags(flags);
 }
 
@@ -1371,12 +1585,15 @@
 	save_flags(flags);
 	cli();
 
-	outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
-	udelay(20);
-	val = inb(MIXER_DATA);
-	udelay(20);
+	if (port >= 0xa0) {
+		val = ess_read (devc, port);
+	} else {
+		outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
 
+		udelay(20);
+		val = inb(MIXER_DATA);
+		udelay(20);
+	}
 	restore_flags(flags);
 
 	return val;
@@ -1400,21 +1617,23 @@
 	devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
 
 	/*
-	* Take care of new ES's specifics...
+	* Take care of ES1887 specifics...
 	*/
-	if (devc->caps & ESSCAP_NEW) {
-		devc->supported_devices		= ES_NEW_MIXER_DEVICES;
-		devc->supported_rec_devices	= ES_NEW_RECORDING_DEVICES;
+	switch (devc->submodel) {
+	case SUBMDL_ES1887:
+		devc->supported_devices		= ES1887_MIXER_DEVICES;
+		devc->supported_rec_devices	= ES1887_RECORDING_DEVICES;
 #ifdef FKS_LOGGING
 printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);
 #endif
 		if (devc->duplex) {
-			devc->iomap				= &es_new_mix;
+			devc->iomap				= &es1887_mix;
 		} else {
 			devc->iomap				= &es_rec_mix;
 		}
-	} else {
-		if (devc->submodel == SUBMDL_ES688) {
+		break;
+	default:
+		if (devc->submodel < 8) {
 			devc->supported_devices		= ES688_MIXER_DEVICES;
 			devc->supported_rec_devices	= ES688_RECORDING_DEVICES;
 			devc->iomap					= &es688_mix;
@@ -1425,10 +1644,10 @@
 			 */
 			devc->supported_devices		= ES1688_MIXER_DEVICES;
 			devc->supported_rec_devices	= ES1688_RECORDING_DEVICES;
-			if (devc->caps & ESSCAP_ES18) {
-				devc->iomap				= &es1688later_mix;
-			} else {
+			if (devc->submodel < 0x10) {
 				devc->iomap				= &es1688_mix;
+			} else {
+				devc->iomap				= &es1688later_mix;
 			}
 		}
 	}
@@ -1440,15 +1659,9 @@
  */
 int ess_mixer_set(sb_devc *devc, int dev, int left, int right)
 {
-	if ((devc->caps & ESSCAP_NEW) && (devc->recmask & (1 << dev))) {
+	if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) {
 		sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right);
 	}
-	/* Set & unmute master volume */
-	if ((devc->caps & ESSCAP_ES18) && (dev == SOUND_MIXER_VOLUME)) {
-		ess_chgmixer (devc, 0x60, 0x7f, 0x3f & ((left * 0x3f + 50) / 100));
-		ess_chgmixer (devc, 0x62, 0x7f, 0x3f & ((right * 0x3f + 50) / 100));
-		return left | (right << 8);
-	}
 	return sb_common_mixer_set (devc, dev, left, right);
 }
 
@@ -1494,6 +1707,7 @@
 				right = (value & 0x0000ff00) >> 8;
 			} else {				/* Turn it off (3)  */
 				left  = 0;
+				left  = 0;
 				right = 0;
 			}
 			sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right);
@@ -1506,7 +1720,7 @@
 {
 	/* This applies to ESS chips with record mixers only! */
 
-	if (devc->caps & ESSCAP_NEW) {
+	if (ess_has_rec_mixer (devc->submodel)) {
 		*mask	= es_rec_set_recmask (devc, *mask);
 		return 1;									/* Applied		*/
 	} else {
@@ -1522,7 +1736,18 @@
 	/*
 	 * Separate actions for ESS chips with a record mixer:
 	 */
-	if (devc->caps & ESSCAP_NEW) {
+	if (ess_has_rec_mixer (devc->submodel)) {
+		switch (devc->submodel) {
+		case SUBMDL_ES1887:
+			/*
+			 * Separate actions for ES1887:
+			 * Change registers 7a and 1c to make the record mixer the
+			 * actual recording source.
+			 */
+			ess_chgmixer(devc, 0x7a, 0x18, 0x08);
+			ess_chgmixer(devc, 0x1c, 0x07, 0x07);
+			break;
+		};
 		/*
 		 * Call set_recmask for proper initialization
 		 */
@@ -1542,80 +1767,50 @@
  *																			*
  ****************************************************************************/
 
+/*
+ * FKS: IRQ may be shared. Hm. And if so? Then What?
+ */
 int ess_midi_init(sb_devc * devc, struct address_info *hw_config)
 {
-	int val;
+	unsigned char   cfg, tmp;
 
-	if (devc->submodel == SUBMDL_ES688) {
-		return 0;				/* ES688 doesn't support MPU401 mode */
+	cfg = ess_getmixer (devc, 0x40) & 0x03;
+
+	if (devc->submodel < 8) {
+		ess_setmixer (devc, 0x40, cfg | 0x03);	/* Enable OPL3 & joystick */
+		return 0;  					 /* ES688 doesn't support MPU401 mode */
 	}
+	tmp = (hw_config->io_base & 0x0f0) >> 4;
 
-	if (hw_config->irq < 2) {
-		hw_config->irq = devc->irq;
+	if (tmp > 3) {
+		ess_setmixer (devc, 0x40, cfg);
+		return 0;
 	}
+	cfg |= tmp << 3;
 
-	if (devc->caps & ESSCAP_PNP) {
-		outb (0x07, devc->pcibase);		/* Selects logical device #1 */
-		outb (0x01, devc->pcibase + 1);
-		outb (0x28, devc->pcibase);
-		val = inb (devc->pcibase + 1) & 0xf0;
-		outb (0x28, devc->pcibase);		/* Sets MPU IRQ */
-		outb (hw_config->irq | val, devc->pcibase + 1);
-		if (hw_config->io_base) {
-			outb (0x64, devc->pcibase);		/* Sets MPU I/O address */
-			outb ((hw_config->io_base & 0xf00) >> 8, devc->pcibase + 1);
-			outb (0x65, devc->pcibase);		/* Sets MPU I/O address */
-			outb (hw_config->io_base & 0xfc, devc->pcibase + 1);
-		} else {
-			outb (0x64, devc->pcibase);		/* Read MPU I/O address */
-			hw_config->io_base = (inb (devc->pcibase + 1) & 0x0f) << 8;
-			outb (0x65, devc->pcibase);		/* Read MPU I/O address */
-			hw_config->io_base |= inb (devc->pcibase + 1) & 0xfc;
-		}
+	tmp = 1;		/* MPU enabled without interrupts */
 
-		ess_setmixer (devc, 0x64, 0xc2);	/* Enable MPU interrupt */
-	} else {
-		if (devc->irq == hw_config->irq && (devc->caps & ESSCAP_IRQ)) {
-			val = 0x43;
-		}
-		else switch (hw_config->irq) {
-			case 11:
-				if (!(devc->caps & ESSCAP_IRQ)) {
-					return 0;
-				}
-				val = 0x63;
-				break;
-			case 2:
-			case 9:
-				val = 0x83;
-				break;
-			case 5:
-				val = 0xa3;
-				break;
-			case 7:
-				val = 0xc3;
-				break;
-			case 10:
-				val = 0xe3;
-				break;
-			default:
-				return 0;
-		}
-		switch (hw_config->io_base) {
-			case 0x300:
-			case 0x310:
-			case 0x320:
-			case 0x330:
-				ess_setmixer (devc, 0x40, val
-								| ((hw_config->io_base & 0x0f0) >> 1));
-				break;
-			default:
-				return 0;
-		}
+	/* May be shared: if so the value is -ve */
+
+	switch (abs(hw_config->irq)) {
+		case 9:
+			tmp = 0x4;
+			break;
+		case 5:
+			tmp = 0x5;
+			break;
+		case 7:
+			tmp = 0x6;
+			break;
+		case 10:
+			tmp = 0x7;
+			break;
+		default:
+			return 0;
 	}
 
-	if (devc->irq == hw_config->irq)	/* Shared IRQ */
-		hw_config->irq = -devc->irq;
+	cfg |= tmp << 5;
+	ess_setmixer (devc, 0x40, cfg | 0x03);
 
 	return 1;
 }
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.3.9/linux/drivers/sound/sb_mixer.c	Mon Apr 12 16:18:27 1999
+++ linux/drivers/sound/sb_mixer.c	Mon Jul  5 19:58:25 1999
@@ -13,6 +13,7 @@
  *
  * Thomas Sailer				: ioctl code reworked (vmalloc/vfree removed)
  * Rolf Fokkens (Dec 20 1998)	: Moved ESS stuff into sb_ess.[ch]
+ * Stanislav Voronyi <stas@esc.kharkov.com>	: Support for AWE 3DSE device (Jun 7 1999)
  */
 
 #include <linux/config.h>
@@ -550,14 +551,37 @@
 	int val, ret;
 
 	/*
-	 * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1).
+	 * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1).
+	 * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1)
+	 *					      or mode==2 put 3DSE state to mode.
 	 */
-	if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) 
-	{
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		sb_setmixer(devc, 0x43, (~val) & 0x01);
-		return 0;
+	if (devc->model == MDL_SB16) {
+		if (cmd == SOUND_MIXER_AGC) 
+		{
+			if (get_user(val, (int *)arg))
+				return -EFAULT;
+			sb_setmixer(devc, 0x43, (~val) & 0x01);
+			return 0;
+		}
+		if (cmd == SOUND_MIXER_3DSE) 
+		{
+			/* I put here 15, but I don't know the exact version.
+			   At least my 4.13 havn't 3DSE, 4.16 has it. */
+			if (devc->minor < 15)
+				return -EINVAL;
+			if (get_user(val, (int *)arg))
+				return -EFAULT;
+			if (val == 0 || val == 1)
+				sb_chgmixer(devc, AWE_3DSE, 0x01, val);
+			else if (val == 2)
+			{
+				ret = sb_getmixer(devc, AWE_3DSE)&0x01;
+				return put_user(ret, (int *)arg);
+			}
+			else
+				return -EINVAL;
+			return 0;
+		}
 	}
 	if (((cmd >> 8) & 0xff) == 'M') 
 	{
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v2.3.9/linux/drivers/sound/sb_mixer.h	Thu Jan  7 09:24:00 1999
+++ linux/drivers/sound/sb_mixer.h	Mon Jul  5 19:58:25 1999
@@ -78,6 +78,11 @@
 #define RIGHT_CHN	1
 
 /*
+ * 3DSE register of AWE32/64
+ */
+#define AWE_3DSE	0x90
+
+/*
  * Mixer registers of ALS007
  */
 #define ALS007_RECORD_SRC	0x6c
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c
--- v2.3.9/linux/drivers/sound/sgalaxy.c	Sun Nov  8 13:56:11 1998
+++ linux/drivers/sound/sgalaxy.c	Mon Jul  5 19:58:25 1999
@@ -2,7 +2,7 @@
  * sound/sgalaxy.c
  *
  * Low level driver for Aztech Sound Galaxy cards.
- * Copyright 1998 Artur Skawina
+ * Copyright 1998 Artur Skawina <skawina@geocities.com>
  *
  * Supported cards:
  *    Aztech Sound Galaxy Waverider Pro 32 - 3D
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.9/linux/drivers/sound/sonicvibes.c	Fri Jun 18 10:45:58 1999
+++ linux/drivers/sound/sonicvibes.c	Mon Jul  5 19:58:25 1999
@@ -2312,9 +2312,9 @@
 };
 
 #ifdef MODULE
-__initfunc(int init_module(void))
+int __init init_module(void)
 #else
-__initfunc(int init_sonicvibes(void))
+int __init init_sonicvibes(void)
 #endif
 {
 	struct sv_state *s;
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v2.3.9/linux/drivers/sound/sound_calls.h	Mon Jan  4 11:37:30 1999
+++ linux/drivers/sound/sound_calls.h	Mon Jul  5 19:58:25 1999
@@ -256,21 +256,39 @@
 void unload_trix_mpu(struct address_info *hw_info);
 void unload_cs4232(struct address_info *hw_info);
 void unload_cs4232_mpu(struct address_info *hw_info);
+void unload_opl3sa_wss(struct address_info *hw_info);
+void unload_opl3sa_sb(struct address_info *hw_info);
+void unload_opl3sa_mpu(struct address_info *hw_info);
 void unload_opl3sa2(struct address_info *hw_info);
 void unload_opl3sa2_mpu(struct address_info *hw_info);
+void unload_opl3sa2_mss(struct address_info *hw_info);
+void unload_softsyn (struct address_info *hw_config);
 
-/* From cs4232.c */
-
+/*	From cs4232.c */
 int probe_cs4232 (struct address_info *hw_config);
 void attach_cs4232 (struct address_info *hw_config);
 int probe_cs4232_mpu (struct address_info *hw_config);
 void attach_cs4232_mpu (struct address_info *hw_config);
 
-/* From opl3sa2.c */
+/*	From opl3sa.c */
+void attach_opl3sa_wss (struct address_info *hw_config);
+int probe_opl3sa_wss (struct address_info *hw_config);
+void attach_opl3sa_sb (struct address_info *hw_config);
+int probe_opl3sa_sb (struct address_info *hw_config);
+void attach_opl3sa_mpu (struct address_info *hw_config);
+int probe_opl3sa_mpu (struct address_info *hw_config);
+
+/*	From opl3sa2.c */
 int probe_opl3sa2 (struct address_info *hw_config);
 void attach_opl3sa2 (struct address_info *hw_config);
 int probe_opl3sa2_mpu (struct address_info *hw_config);
 void attach_opl3sa2_mpu (struct address_info *hw_config);
+int probe_opl3sa2_mss (struct address_info *hw_config);
+void attach_opl3sa2_mss (struct address_info *hw_config);
+
+/*	From softoss.c */
+void attach_softsyn_card (struct address_info *hw_config);
+int probe_softsyn (struct address_info *hw_config);
 
 /*	From maui.c */
 void attach_maui(struct address_info * hw_config);
@@ -291,12 +309,12 @@
 int probe_waveartist(struct address_info *hw_config);
 void unload_waveartist(struct address_info *hw_config);
 
-/*      From wavefront.c */
+/*	From wavefront.c */
 void attach_wavefront (struct address_info *hw_config);
 int probe_wavefront (struct address_info *hw_config);
 void unload_wavefront (struct address_info *hw_config);
 
-/*      From wf_midi.c */
+/*	From wf_midi.c */
 void attach_wf_mpu(struct address_info * hw_config);
 int probe_wf_mpu(struct address_info *hw_config);
 void unload_wf_mpu(struct address_info *hw_config);
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c
--- v2.3.9/linux/drivers/sound/sound_syms.c	Mon Jan  4 11:37:30 1999
+++ linux/drivers/sound/sound_syms.c	Mon Jul  5 19:58:25 1999
@@ -3,6 +3,9 @@
  *	modulespace.
  *
  *      (C) Copyright 1997      Alan Cox, Licensed under the GNU GPL
+ *
+ *	Thu May 27 1999 Andrew J. Kroll <ag784@freenet..buffalo..edu>
+ *	left out exported symbol... fixed
  */
 
 #include <linux/module.h>
@@ -43,6 +46,7 @@
 
 EXPORT_SYMBOL(load_mixer_volumes);
 
+EXPORT_SYMBOL(trace_init); /* oops! this is needed for maui.c -- AJK */
 
 EXPORT_SYMBOL(conf_printf);
 EXPORT_SYMBOL(conf_printf2);
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.3.9/linux/drivers/sound/trix.c	Sun Mar  7 15:22:06 1999
+++ linux/drivers/sound/trix.c	Mon Jul  5 19:58:25 1999
@@ -42,6 +42,12 @@
 
 static int mpu = 0;
 
+#ifdef TRIX_JOYSTICK
+static int joystick=1;
+#else
+static int joystick=0;
+#endif
+
 static unsigned char trix_read(int addr)
 {
 	outb(((unsigned char) addr), 0x390);	/* MT-0002-PC ASIC address */
@@ -196,9 +202,8 @@
 
 	if (ret)
 	{
-#ifdef TRIX_ENABLE_JOYSTICK
-		trix_write(0x15, 0x80);
-#endif
+		if(joystick==1)
+			trix_write(0x15, 0x80);
 		request_region(0x390, 2, "AudioTrix");
 	}
 	return ret;
@@ -477,7 +482,7 @@
 MODULE_PARM(sb_irq,"i");
 MODULE_PARM(mpu_io,"i");
 MODULE_PARM(mpu_irq,"i");
-
+MODULE_PARM(joystick, "i");
 struct address_info config;
 struct address_info sb_config;
 struct address_info mpu_config;
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c
--- v2.3.9/linux/drivers/sound/wavfront.c	Tue May 11 23:40:50 1999
+++ linux/drivers/sound/wavfront.c	Mon Jul  5 19:58:25 1999
@@ -2474,8 +2474,7 @@
 	return (1);
 }
 
-__initfunc (static int detect_wavefront (int irq, int io_base))
-
+static int __init detect_wavefront (int irq, int io_base)
 {
 	unsigned char   rbuf[4], wbuf[4];
 
@@ -2653,8 +2652,7 @@
 	return 1;
 }
 
-__initfunc (static int wavefront_config_midi (void)) 
-
+static int __init wavefront_config_midi (void)
 {
 	unsigned char rbuf[4], wbuf[4];
     
@@ -2728,7 +2726,6 @@
 
 static int
 wavefront_do_reset (int atboot)
-
 {
 	char voices[1];
 
@@ -2832,7 +2829,6 @@
 
 static int
 wavefront_init (int atboot)
-
 {
 	int samples_are_from_rom;
 
@@ -2861,7 +2857,7 @@
 	return (0);
 }
 
-__initfunc (static int install_wavefront (void))
+static int __init install_wavefront (void)
 
 {
 	if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
@@ -2919,7 +2915,7 @@
 #endif OSS_SUPPORT_SEQ
 	uninstall_wf_mpu ();
 }
-
+
 /***********************************************************************/
 /*   WaveFront FX control                                              */
 /***********************************************************************/
@@ -2955,8 +2951,7 @@
 	return (1);
 }
 
-__initfunc (static int detect_wffx (void))
-
+static int __init detect_wffx (void)
 {
 	/* This is a crude check, but its the best one I have for now.
 	   Certainly on the Maui and the Tropez, wffx_idle() will
@@ -2972,8 +2967,7 @@
 	return 0;
 }	
 
-__initfunc (static int attach_wffx (void))
-
+static int __init attach_wffx (void)
 {
 	if ((dev.fx_mididev = sound_alloc_mididev ()) < 0) {
 		printk (KERN_WARNING LOGNAME "cannot install FX Midi driver\n");
diff -u --recursive --new-file v2.3.9/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c
--- v2.3.9/linux/drivers/sound/wf_midi.c	Thu Jan 14 22:59:47 1999
+++ linux/drivers/sound/wf_midi.c	Mon Jul  5 19:58:25 1999
@@ -803,7 +803,7 @@
 	return 0;
 }
 
-__initfunc (static int detect_wf_mpu (int irq, int io_base))
+static int __init detect_wf_mpu (int irq, int io_base)
 
 {
 	if (check_region (io_base, 2)) {
@@ -820,8 +820,7 @@
 	return 0;
 }
 
-__initfunc (int install_wf_mpu (void)) 
-
+int __init install_wf_mpu (void)
 {
 	if ((phys_dev->devno = sound_alloc_mididev()) < 0){
 
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- v2.3.9/linux/drivers/usb/CREDITS	Tue Jun  8 10:52:26 1999
+++ linux/drivers/usb/CREDITS	Thu Jul  1 10:45:57 1999
@@ -29,7 +29,7 @@
 THANKS file in Inaky's driver):
 
         The following corporations have helped us in the development
-of Linux USB / UUSBD:
+        of Linux USB / UUSBD:
 
         - USAR Systems provided us with one of their excellent USB
           Evaluation Kits. It allows us to test the Linux-USB driver
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/hub.h linux/drivers/usb/hub.h
--- v2.3.9/linux/drivers/usb/hub.h	Wed Apr 21 05:41:59 1999
+++ linux/drivers/usb/hub.h	Thu Jul  8 15:19:55 1999
@@ -12,6 +12,7 @@
 /*
  * Port feature numbers
  */
+#define USB_PORT_FEAT_CONNECTION	0
 #define USB_PORT_FEAT_ENABLE		1
 #define USB_PORT_FEAT_SUSPEND		2
 #define USB_PORT_FEAT_OVER_CURRENT	3
@@ -40,7 +41,7 @@
 #define USB_PORT_STAT_C_OVERCURRENT	0x0008
 #define USB_PORT_STAT_C_RESET		0x0010
 
-/* Characteristics */
+/* wHubCharacteristics (masks) */
 #define HUB_CHAR_LPSM		0x0003
 #define HUB_CHAR_COMPOUND	0x0004
 #define HUB_CHAR_OCPM		0x0018
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.3.9/linux/drivers/usb/ohci-debug.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/ohci-debug.c	Sat Jul  3 18:07:29 1999
@@ -119,10 +119,9 @@
 		(td_toggle < 2) ? " " :
 		(td_toggle & 1) ? "Data1" : "Data0",
 		"ErrorCnt ", td_errcnt);
-	printk(KERN_DEBUG "        ComplCode 0x%x, %sAccessed, %sActive\n",
+	printk(KERN_DEBUG "        ComplCode 0x%x, %sAccessed\n",
 		td_cc,
-		td_cc_accessed(*td) ? "" : "Not ",
-		td_active(*td) ? "" : "Not ");
+		td_cc_accessed(*td) ? "" : "Not ");
 
 	printk(KERN_DEBUG "        %s%s\n",
 		td_allocated(*td) ? "Allocated" : "Free",
@@ -159,7 +158,7 @@
 		if (td_dummy(*cur_td)) break;
 	}
 
-	printk(KERN_DEBUG "--- End  TD Chain %lx: ---\n", virt_to_bus(td));
+	printk(KERN_DEBUG "--- End  TD Chain %lx. ---\n", virt_to_bus(td));
 } /* show_ohci_td_chain () */
 
 
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.9/linux/drivers/usb/ohci.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/ohci.c	Sat Jul  3 18:07:29 1999
@@ -179,27 +179,27 @@
 /* .......... */
 
 
-inline void ohci_start_control(struct ohci *ohci)
+void ohci_start_control(struct ohci *ohci)
 {
 	/* tell the HC to start processing the control list */
 	writel_set(OHCI_USB_CLE, &ohci->regs->control);
 	writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
 }
 
-inline void ohci_start_bulk(struct ohci *ohci)
+void ohci_start_bulk(struct ohci *ohci)
 {
 	/* tell the HC to start processing the bulk list */
 	writel_set(OHCI_USB_BLE, &ohci->regs->control);
 	writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
 }
 
-inline void ohci_start_periodic(struct ohci *ohci)
+void ohci_start_periodic(struct ohci *ohci)
 {
 	/* enable processing periodic (intr) transfers starting next frame */
 	writel_set(OHCI_USB_PLE, &ohci->regs->control);
 }
 
-inline void ohci_start_isoc(struct ohci *ohci)
+void ohci_start_isoc(struct ohci *ohci)
 {
 	/* enable processing isoc. transfers starting next frame */
 	writel_set(OHCI_USB_IE, &ohci->regs->control);
@@ -658,7 +658,7 @@
  * 	dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
  * 	toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1
  */
-inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
+struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
 {
 	/* hardware fields */
 	td->info = cpu_to_le32(OHCI_TD_CC_NEW |
@@ -846,16 +846,20 @@
 		return 0;
 
 	/* if cur_buf is 0, all data has been transferred */
-	bus_data_end = td->cur_buf ? td->cur_buf : td->buf_end;
+	if (!td->cur_buf) {
+		return td->buf_end - bus_data_start + 1;
+	}
+
+	bus_data_end = td->cur_buf;
 
 	/* is it on the same page? */
 	if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) {
-		result = bus_data_end - bus_data_start + 1;
+		result = bus_data_end - bus_data_start;
 	} else {
 		/* compute the amount transferred on the first page */
 		result = 0x1000 - (bus_data_start & 0xfff);
 		/* add the amount done in the second page */
-		result += (bus_data_end & 0xfff) + 1;
+		result += (bus_data_end & 0xfff);
 	}
 
 	return result;
@@ -1190,16 +1194,12 @@
 	if (stats == USB_ST_NOERROR)
 		req->_bytes_done += len;
 
-#ifdef OHCI_DEBUG
-	printk(KERN_DEBUG "ohci_bulk_td_handler %d bytes done\n", req->_bytes_done);
-#endif
-
 	/* call the real completion handler when done or on an error */
 	if ((stats != USB_ST_NOERROR) ||
 	    (req->_bytes_done >= req->length && req->completion != NULL)) {
 		*req->bytes_transferred_p += req->_bytes_done;
 #ifdef OHCI_DEBUG
-		printk(KERN_DEBUG "usb-ohci: bulk request %p ending after %d bytes\n", req, req->_bytes_done);
+		printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req);
 #endif
 		req->completion(stats, buffer, req->_bytes_done, req->dev_id);
 	}
@@ -1282,13 +1282,13 @@
 
 
 #ifdef OHCI_DEBUG
-/*	if (MegaDebug) { */
-	/* complete transaction debugging output (before) */
+	if (MegaDebug) {
+	/* complete request debugging output (before) */
 	printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed));
 	show_ohci_ed(bulk_ed);
 	printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td));
 	show_ohci_td_chain(head_td);
-/*	} */
+	}
 #endif
 
 	/* Give the ED to the HC */
@@ -1303,6 +1303,9 @@
 
 static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_id)
 {
+#ifdef OHCI_DEBUG
+	printk("ohci_bulk_msg_completed %x, %p, %d, %p\n", stats, buffer, len, dev_id);
+#endif
 	if (dev_id != NULL) {
 		int *completion_status = (int *)dev_id;
 		*completion_status = stats;
@@ -1320,12 +1323,15 @@
 	struct ohci_bulk_request_state req;
 	struct ohci_ed *req_ed;
 
-	/* ....... */
-
 #ifdef OHCI_DEBUG 
 	printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p);
 #endif
 
+	/* initialize bytes transferred to nothing */
+	*bytes_transferred_p = 0;
+
+	/* Hopefully this is similar to the "URP" (USB Request Packet) code
+	 * that michael gee is working on... */
 	req.usb_dev = usb_dev;
 	req.pipe = pipe;
 	req.data = data;
@@ -1345,9 +1351,44 @@
 	/* FIXME this should to wait for a caller specified time... */
 	schedule_timeout(HZ*5);
 
+	/* it'll only stay in this state of the request never finished */
+	if (completion_status == USB_ST_INTERNALERROR) {
+		struct ohci_device *dev = usb_to_ohci(usb_dev);
+		struct ohci_regs *regs = dev->ohci->regs;
+
 #ifdef OHCI_DEBUG
-	printk(KERN_DEBUG "ohci_bulk_msg request completed or timed out w/ status %x\n", completion_status);
+		printk(KERN_DEBUG "ohci_bulk_msg timing out\n");
 #endif
+		/* XXX This code should go into a function used to stop
+		 * a previously requested bulk transfer. -greg */
+
+		/* stop the transfer & collect the number of bytes */
+		ohci_wait_for_ed_safe(regs, req_ed, HCD_ED_BULK);
+
+		/* Get the number of bytes transferred out of the head TD
+		 * on the ED if it didn't finish while we were waiting. */
+		if ( ed_head_td(req_ed) &&
+		     (ed_head_td(req_ed) != ed_tail_td(req_ed)) ) {
+			struct ohci_td *partial_td;
+			partial_td = bus_to_virt(ed_head_td(req_ed));
+
+#ifdef OHCI_DEBUG
+			if (MegaDebug) {
+			show_ohci_td(partial_td);
+			}
+#endif
+			/* Record the bytes as transferred */
+			*bytes_transferred_p += ohci_td_bytes_done(partial_td);
+			
+			/* If there was an unreported error, return it.
+			 * Otherwise return a timeout */
+			completion_status = OHCI_TD_CC_GET(partial_td->info);
+			if (completion_status == USB_ST_NOERROR) {
+				completion_status = USB_ST_TIMEOUT;
+			}
+		}
+
+	}
 
 	remove_wait_queue(&bulk_wakeup, &wait);
 
@@ -1356,7 +1397,7 @@
 	ohci_free_ed(req_ed);	 /* return it to the pool */
 
 #ifdef OHCI_DEBUG
-	printk(KERN_DEBUG "ohci_bulk_msg done.\n");
+	printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p);
 #endif
 
 	return completion_status;
@@ -1761,7 +1802,7 @@
 	struct ohci_td *td;		/* used for walking the list */
 
 	/* um... isn't this dangerous to do in an interrupt handler? -greg */
-	spin_lock(&ohci_edtd_lock);
+//	spin_lock(&ohci_edtd_lock);
 
 	/* create the FIFO ordered donelist */
 	td = ohci_reverse_donelist(ohci);
@@ -1832,6 +1873,7 @@
 
 			/* insert it back on its ED */
 			ohci_add_td_to_ed(td, td, td->ed);
+			ohci_unhalt_ed(td->ed);
 		} else {
 			/* return it to the pool of free TDs */
 			if (can_auto_free(*td))
@@ -1841,7 +1883,7 @@
 		td = next_td;
 	}
 
-	spin_unlock(&ohci_edtd_lock);
+//	spin_unlock(&ohci_edtd_lock);
 } /* ohci_reap_donelist() */
 
 
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.9/linux/drivers/usb/ohci.h	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/ohci.h	Sat Jul  3 18:07:29 1999
@@ -71,7 +71,6 @@
 #define td_cc_notaccessed(td)	((le32_to_cpup(&(td).info) >> 29) == 7)
 #define td_cc_accessed(td)	((le32_to_cpup(&(td).info) >> 29) != 7)
 #define td_cc_noerror(td)	(((le32_to_cpup(&(td).info)) & OHCI_TD_CC) == 0)
-#define td_active(td)	(!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
 #define td_done(td)	(td_cc_noerror((td)) || (td_errorcount((td)) == 3))
 
 /*
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.9/linux/drivers/usb/printer.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/printer.c	Thu Jul  8 15:19:55 1999
@@ -124,6 +124,7 @@
 		return -EBUSY;
 	}
 	if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) {
+		p->isopen = 0;
 		return -ENOMEM;
 	}
 
@@ -166,7 +167,6 @@
 	do {
 		char *obuf = p->obuf;
 		unsigned long thistime;
-		partial = 0;
 
 		thistime = copy_size = (count > p->maxout) ? p->maxout : count;
 		if (copy_from_user(p->obuf, buffer, copy_size))
@@ -303,7 +303,11 @@
 	minor_data[i] = PPDATA(dev->private);
 	minor_data[i]->minor = i;
 	minor_data[i]->pusb_dev = dev;
-	minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16;
+	/* The max packet size can't be more than 64 (& will be 64 for
+	 * any decent bulk device); this calculation was silly.  -greg
+	 * minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16;
+	 */
+	minor_data[i]->maxout = 8192;
 	if (minor_data[i]->maxout > PAGE_SIZE) {
                 minor_data[i]->maxout = PAGE_SIZE;
 	}
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.9/linux/drivers/usb/uhci.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/uhci.c	Thu Jul  8 15:19:55 1999
@@ -32,14 +32,9 @@
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
-
-#include <linux/sched.h>
 #include <linux/unistd.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
-
-
 #include <asm/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -70,7 +65,7 @@
     	    return USB_ST_BITSTUFF;
     if (status & 0x04)	{			/* CRC/Timeout */
 	if (dir_out)
-    	    return USB_ST_TIMEOUT;
+    	    return USB_ST_NORESPONSE;
 	else
 	    return USB_ST_CRC;
     }
@@ -104,7 +99,7 @@
 		if (status) {
 			/* must reset the toggle on first error */
     			if (uhci_debug) {
-			    printk("Set toggle from %x rval %d\n", (unsigned int)tmp, rval ? *rval : 0);
+			    printk("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);
 			break;
@@ -1442,10 +1437,12 @@
 
 	/* We need exactly one page (per UHCI specs), how convenient */
 	uhci->fl = (void *)__get_free_page(GFP_KERNEL);
+	if (!uhci->fl)
+		goto au_free_uhci;
 
 	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
 	if (!bus)
-		return NULL;
+		goto au_free_fl;
 
 	memset(bus, 0, sizeof(*bus));
 
@@ -1465,7 +1462,7 @@
 	 */
 	usb = uhci_usb_allocate(NULL);
 	if (!usb)
-		return NULL;
+		goto au_free_bus;
 
 	usb->bus = bus;
 	dev = usb_to_uhci(usb);
@@ -1536,6 +1533,18 @@
 	}
 
 	return uhci;
+
+/*
+ * error exits:
+ */
+
+au_free_bus:
+	kfree (bus);
+au_free_fl:
+	free_page ((unsigned long)uhci->fl);
+au_free_uhci:
+	kfree (uhci);
+	return NULL;
 }
 
 
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.9/linux/drivers/usb/uhci.h	Tue Jun 22 14:42:27 1999
+++ linux/drivers/usb/uhci.h	Thu Jul  8 15:31:47 1999
@@ -167,12 +167,12 @@
  * Linus:
  *
  *  generic-iso-QH  ->  dev1-iso-QH  ->  generic-irq-QH  ->  dev1-irq-QH  -> ...
- *       |                       |                  |                   |
- *      End          dev1-iso-TD1          End            dev1-irq-TD1
- *                       |
- *                   dev1-iso-TD2
- *                       |
- *                      ....
+ *       |                  |                  |                   |
+ *      End             dev1-iso-TD1          End            dev1-irq-TD1
+ *                          |
+ *                      dev1-iso-TD2
+ *                          |
+ *                        ....
  *
  * This may vary a bit (the UHCI docs don't explicitly say you can put iso
  * transfers in QH's and all of their pictures don't have that either) but
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.9/linux/drivers/usb/usb.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/usb.c	Thu Jul  8 15:31:47 1999
@@ -260,7 +260,7 @@
 
 static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len)
 {
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7);
+	int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE);
 	int i;
 
 	if (parsed < 0)
@@ -284,7 +284,7 @@
 static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len)
 {
 	int i;
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9);
+	int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE);
 	int retval;
 
 	if (parsed < 0)
@@ -848,29 +848,40 @@
 int usb_get_configuration(struct usb_device *dev)
 {
 	unsigned int cfgno;
-	unsigned char buffer[400];
 	unsigned char * bufptr;
-	
+	unsigned char * buffer;
+	int parse;
+
+	buffer = (unsigned char *) __get_free_page (GFP_KERNEL);
+	if (!buffer)
+		return -1;
+
 	bufptr = buffer;
 	for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) {
 		unsigned int size;
   		/* Get the first 8 bytes - guaranteed */
-	  	if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8))
+	  	if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) {
+			__free_page ((struct page *) buffer);
 	    		return -1;
+		}
 
   	  	/* Get the full buffer */
 	  	size = le16_to_cpup((unsigned short *)(bufptr+2));
-	  	if (bufptr+size > buffer+sizeof(buffer)) {
+	  	if (bufptr+size > buffer+PAGE_SIZE) {
 			printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
-			size = buffer+sizeof(buffer)-bufptr;
+			size = buffer+PAGE_SIZE-bufptr;
 		}
-		if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size))
+		if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) {
+			__free_page ((struct page *) buffer);
 			return -1;
+		}
 			
 		/* Prepare for next configuration */
 		bufptr += size;
 	}
-	return usb_parse_configuration(dev, buffer, bufptr - buffer);
+	parse = usb_parse_configuration(dev, buffer, bufptr - buffer);
+	__free_page ((struct page *) buffer);
+	return parse;
 }
 
 int usb_get_stringtable(struct usb_device *dev)
diff -u --recursive --new-file v2.3.9/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.9/linux/drivers/usb/usb.h	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/usb.h	Thu Jul  8 15:31:47 1999
@@ -31,9 +31,16 @@
 } devrequest;
 
 /*
- * Class codes
+ * Device and/or Interface Class codes
  */
+#define USB_CLASS_PER_INTERFACE		0	/* for DeviceClass */
+#define USB_CLASS_AUDIO			1
+#define USB_CLASS_COMM			2
+#define USB_CLASS_HID			3
+#define USB_CLASS_PRINTER		7
+#define USB_CLASS_MASS_STORAGE		8
 #define USB_CLASS_HUB			9
+#define USB_CLASS_VENDOR_SPEC		0xff
 
 /*
  * Descriptor types
@@ -48,6 +55,28 @@
 #define USB_DT_HID			0x21
 
 /*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE		18
+#define USB_DT_CONFIG_SIZE		9
+#define USB_DT_INTERFACE_SIZE		9
+#define USB_DT_ENDPOINT_SIZE		7
+#define USB_DT_HUB_NONVAR_SIZE		7
+
+/*
+ * USB Request Type and Endpoint Directions
+ */
+#define USB_DIR_OUT			0
+#define USB_DIR_IN			0x80
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_OUT			0xe1
+#define USB_PID_IN			0x69
+#define USB_PID_SETUP			0x2d
+
+/*
  * Standard requests
  */
 #define USB_REQ_GET_STATUS		0x00
@@ -97,16 +126,16 @@
 #define USB_RT_HIDD			(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
 
 /* 
- * Status codes 
+ * Status codes (these follow an OHCI controllers condition codes)
  */
 #define USB_ST_NOERROR		0x0
 #define USB_ST_CRC		0x1
 #define USB_ST_BITSTUFF		0x2
-#define USB_ST_DTMISMATCH	0x3
+#define USB_ST_DTMISMATCH	0x3	/* data toggle mismatch */
 #define USB_ST_STALL		0x4
-#define USB_ST_TIMEOUT		0x5
-#define USB_ST_PIDCHECK		0x6
-#define USB_ST_PIDUNDEF		0x7
+#define USB_ST_NORESPONSE	0x5	/* device not responding/handshaking */
+#define USB_ST_PIDCHECK		0x6	/* Check bits on PID failed */
+#define USB_ST_PIDUNDEF		0x7	/* PID unexpected/undefined */
 #define USB_ST_DATAOVERRUN	0x8
 #define USB_ST_DATAUNDERRUN	0x9
 #define USB_ST_RESERVED1	0xA
@@ -118,6 +147,7 @@
 
 /* internal errors */
 #define USB_ST_REMOVED		0x100
+#define USB_ST_TIMEOUT		0x110
 #define USB_ST_INTERNALERROR	-1
 
 /*
@@ -275,7 +305,7 @@
 struct usb_device {
 	int devnum;			/* Device number on USB bus */
 	int slow;			/* Slow device? */
-	int maxpacketsize;		/* Maximum packet size */
+	int maxpacketsize;		/* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */
 	int toggle[2];			/* one bit for each endpoint ([0] = IN, [1] = OUT) */
 	int halted;			/* endpoint halts */
 	struct usb_config_descriptor *actconfig;/* the active configuration */
@@ -342,16 +372,16 @@
  * Let's not fall in that trap. We'll just encode it as a simple
  * unsigned int. The encoding is:
  *
+ *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64)
+ *  - direction:	bit 7		(0 = Host-to-Device, 1 = Device-to-Host)
  *  - device:		bits 8-14
  *  - endpoint:		bits 15-18
  *  - Data0/1:		bit 19
- *  - direction:	bit 7		(0 = Host-to-Device, 1 = Device-to-Host)
- *  - speed:		bit 26		(0 = High, 1 = Low Speed)
- *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64)
+ *  - speed:		bit 26		(00 = Full, 01 = Low Speed)
  *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
  *
  * Why? Because it's arbitrary, and whatever encoding we select is really
- * up to us. This one happens to share a lot of bit positions with the UCHI
+ * up to us. This one happens to share a lot of bit positions with the UHCI
  * specification, so that much of the uhci driver can just mask the bits
  * appropriately.
  */
@@ -372,6 +402,7 @@
 #define usb_pipebulk(pipe)	(usb_pipetype((pipe)) == 3)
 
 #define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
+#define PIPE_DEVEP_MASK		0x0007ff00
 
 /* The D0/D1 toggle bits */
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
@@ -393,7 +424,7 @@
 	return (dev->slow << 26);
 }
 
-/* Create control pipes.. */
+/* Create various pipes... */
 #define usb_sndctrlpipe(dev,endpoint)	((2 << 30) | __create_pipe(dev,endpoint))
 #define usb_rcvctrlpipe(dev,endpoint)	((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
 #define usb_sndisocpipe(dev,endpoint)	((0 << 30) | __create_pipe(dev,endpoint))
diff -u --recursive --new-file v2.3.9/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.9/linux/drivers/video/Makefile	Wed Jun 30 13:38:20 1999
+++ linux/drivers/video/Makefile	Thu Jul  1 10:57:36 1999
@@ -192,9 +192,11 @@
 
 ifeq ($(CONFIG_FB_TGA),y)
 L_OBJS += tgafb.o
+CONFIG_FBGEN_BUILTIN = y
 else
   ifeq ($(CONFIG_FB_TGA),m)
   M_OBJS += tgafb.o
+  CONFIG_FBGEN_MODULE = y
   endif
 endif
 
diff -u --recursive --new-file v2.3.9/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.9/linux/drivers/video/fbmem.c	Thu May 13 23:48:20 1999
+++ linux/drivers/video/fbmem.c	Thu Jul  1 10:57:36 1999
@@ -74,6 +74,7 @@
 extern void imsttfb_setup(char *options, int *ints);
 extern void dnfb_init(void);
 extern void tgafb_init(void);
+extern void tgafb_setup(char *options, int *ints);
 extern void virgefb_init(void);
 extern void virgefb_setup(char *options, int *ints);
 extern void resolver_video_setup(char *options, int *ints);
@@ -158,7 +159,7 @@
 	{ "s3trio", s3triofb_init, s3triofb_setup },
 #endif 
 #ifdef CONFIG_FB_TGA
-	{ "tga", tgafb_init, NULL },
+	{ "tga", tgafb_init, tgafb_setup },
 #endif
 #ifdef CONFIG_FB_VIRGE
 	{ "virge", virgefb_init, virgefb_setup },
diff -u --recursive --new-file v2.3.9/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.3.9/linux/drivers/video/tgafb.c	Mon Dec 21 14:48:04 1998
+++ linux/drivers/video/tgafb.c	Thu Jul  1 10:57:36 1999
@@ -1,27 +1,29 @@
 /*
  *  linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
  *
- *	Copyright (C) 1997 Geert Uytterhoeven
+ *	Copyright (C) 1999 Martin Lucina, Tom Zerucha
+ *  
+ *  $Id: tgafb.c,v 1.12 1999/07/01 13:39:23 mato Exp $
  *
- *  This driver is partly based on the original TGA console driver
+ *  This driver is partly based on the original TGA framebuffer device, which 
+ *  was partly based on the original TGA console driver, which are
  *
- *	Copyright (C) 1995  Jay Estabrook
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *	Copyright (C) 1995 Jay Estabrook
  *
  *  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.
  */
 
-
 /* KNOWN PROBLEMS/TO DO ===================================================== *
  *
  *	- How to set a single color register on 24-plane cards?
  *
- *	- Hardware cursor (useful for other graphics boards too)
- *
- *	- Support for more resolutions
+ *	- Hardware cursor/other text acceleration methods
  *
  *	- Some redraws can stall kernel for several seconds
+ *	  [This should now be solved by the fast memmove() patch in 2.3.6]
  *
  * KNOWN PROBLEMS/TO DO ==================================================== */
 
@@ -45,477 +47,459 @@
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb32.h>
+#include "tgafb.h"
 
 
-/* TGA hardware description (minimal) */
-/*
- * Offsets within Memory Space
- */
-#define	TGA_ROM_OFFSET			0x0000000
-#define	TGA_REGS_OFFSET			0x0100000
-#define	TGA_8PLANE_FB_OFFSET		0x0200000
-#define	TGA_24PLANE_FB_OFFSET		0x0804000
-#define	TGA_24PLUSZ_FB_OFFSET		0x1004000
-
-#define	TGA_PLANEMASK_REG		0x0028
-#define	TGA_MODE_REG			0x0030
-#define	TGA_RASTEROP_REG		0x0034
-#define	TGA_DEEP_REG			0x0050
-#define	TGA_PIXELMASK_REG		0x005c
-#define	TGA_CURSOR_BASE_REG		0x0060
-#define	TGA_HORIZ_REG			0x0064
-#define	TGA_VERT_REG			0x0068
-#define	TGA_BASE_ADDR_REG		0x006c
-#define	TGA_VALID_REG			0x0070
-#define	TGA_CURSOR_XY_REG		0x0074
-#define	TGA_INTR_STAT_REG		0x007c
-#define	TGA_RAMDAC_SETUP_REG		0x00c0
-#define	TGA_BLOCK_COLOR0_REG		0x0140
-#define	TGA_BLOCK_COLOR1_REG		0x0144
-#define	TGA_CLOCK_REG			0x01e8
-#define	TGA_RAMDAC_REG			0x01f0
-#define	TGA_CMD_STAT_REG		0x01f8
-
-/*
- * useful defines for managing the BT485 on the 8-plane TGA
- */
-#define	BT485_READ_BIT			0x01
-#define	BT485_WRITE_BIT			0x00
-
-#define	BT485_ADDR_PAL_WRITE		0x00
-#define	BT485_DATA_PAL			0x02
-#define	BT485_PIXEL_MASK		0x04
-#define	BT485_ADDR_PAL_READ		0x06
-#define	BT485_ADDR_CUR_WRITE		0x08
-#define	BT485_DATA_CUR			0x0a
-#define	BT485_CMD_0			0x0c
-#define	BT485_ADDR_CUR_READ		0x0e
-#define	BT485_CMD_1			0x10
-#define	BT485_CMD_2			0x12
-#define	BT485_STATUS			0x14
-#define	BT485_CMD_3			0x14
-#define	BT485_CUR_RAM			0x16
-#define	BT485_CUR_LOW_X			0x18
-#define	BT485_CUR_HIGH_X		0x1a
-#define	BT485_CUR_LOW_Y			0x1c
-#define	BT485_CUR_HIGH_Y		0x1e
-
-/*
- * useful defines for managing the BT463 on the 24-plane TGAs
- */
-#define	BT463_ADDR_LO		0x0
-#define	BT463_ADDR_HI		0x1
-#define	BT463_REG_ACC		0x2
-#define	BT463_PALETTE		0x3
+    /*
+     *  Global declarations
+     */
 
-#define	BT463_CUR_CLR_0		0x0100
-#define	BT463_CUR_CLR_1		0x0101
+static struct tgafb_info fb_info;
+static struct tgafb_par current_par;
+static int current_par_valid = 0;
+static struct display disp;
 
-#define	BT463_CMD_REG_0		0x0201
-#define	BT463_CMD_REG_1		0x0202
-#define	BT463_CMD_REG_2		0x0203
+static char __initdata default_fontname[40] = { 0 };
+static struct fb_var_screeninfo default_var;
+static int default_var_valid = 0;
 
-#define	BT463_READ_MASK_0	0x0205
-#define	BT463_READ_MASK_1	0x0206
-#define	BT463_READ_MASK_2	0x0207
-#define	BT463_READ_MASK_3	0x0208
+static int currcon = 0;
 
-#define	BT463_BLINK_MASK_0	0x0209
-#define	BT463_BLINK_MASK_1	0x020a
-#define	BT463_BLINK_MASK_2	0x020b
-#define	BT463_BLINK_MASK_3	0x020c
+#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
 
-#define	BT463_WINDOW_TYPE_BASE	0x0300
+static struct { u_char red, green, blue, pad; } palette[256];
+#ifdef FBCON_HAS_CFB32
+static u32 fbcon_cfb32_cmap[16];
+#endif
 
 
-int tga_type;
-unsigned int tga_mem_base;
-unsigned long tga_fb_base;
-unsigned long tga_regs_base;
+    /*
+     *  Hardware presets
+     */
 
-static unsigned int fb_offset_presets[4] __initdata = {
+static unsigned int fb_offset_presets[4] = {
 	TGA_8PLANE_FB_OFFSET,
 	TGA_24PLANE_FB_OFFSET,
 	0xffffffff,
 	TGA_24PLUSZ_FB_OFFSET
 };
 
-static unsigned int deep_presets[4] __initdata = {
+static unsigned int deep_presets[4] = {
   0x00014000,
   0x0001440d,
   0xffffffff,
   0x0001441d
 };
 
-static unsigned int rasterop_presets[4] __initdata = {
+static unsigned int rasterop_presets[4] = {
   0x00000003,
   0x00000303,
   0xffffffff,
   0x00000303
 };
 
-static unsigned int mode_presets[4] __initdata = {
+static unsigned int mode_presets[4] = {
   0x00002000,
   0x00002300,
   0xffffffff,
   0x00002300
 };
 
-static unsigned int base_addr_presets[4] __initdata = {
+static unsigned int base_addr_presets[4] = {
   0x00000000,
   0x00000001,
   0xffffffff,
   0x00000001
 };
 
-#define TGA_WRITE_REG(v,r) \
-	{ writel((v), tga_regs_base+(r)); mb(); }
-
-#define TGA_READ_REG(r) readl(tga_regs_base+(r))
-
-#define BT485_WRITE(v,r) \
-	  TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG);		\
-	  TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
-
-#define BT463_LOAD_ADDR(a) \
-	TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
-	TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
-	TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
-	TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
+const unsigned int bt463_cursor_source[4] = {
+  0xffff0000, 0x00000000, 0x00000000, 0x00000000
+};
 
-#define BT463_WRITE(m,a,v) \
-	BT463_LOAD_ADDR((a)); \
-	TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
-	TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
 
+    /*
+     *  Predefined video modes
+     *  This is a subset of the standard VESA modes, recalculated from XFree86.
+     *
+     *  XXX Should we store these in terms of the encoded par structs? Even better,
+     *      fbcon should provide a general mechanism for doing something like this.
+     */
 
-unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
+static struct fb_videomode tgafb_predefined[] __initdata = {
+    { "640x480-60", {
+	640, 480, 640, 480, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "800x600-56", {
+	800, 600, 800, 600, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 27777, 128, 24, 22, 1, 72, 2,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "640x480-72", {
+	640, 480, 640, 480, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 31746, 144, 40, 30, 8, 40, 3,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "800x600-60", {
+	800, 600, 800, 600, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "800x600-72", {
+	800, 600, 800, 600, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 20000, 64, 56, 23, 37, 120, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-60", {
+	1024, 768, 1024, 768, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 15384, 168, 8, 29, 3, 144, 6,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1152x864-60", {
+	1152, 864, 1152, 864, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 11123, 208, 64, 16, 4, 256, 8,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-70", {
+	1024, 768, 1024, 768, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 13333, 144, 24, 29, 3, 136, 6,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-76", {
+	1024, 768, 1024, 768, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 11764, 208, 8, 36, 16, 120, 3,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1152x864-70", {
+	1152, 864, 1152, 864, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 10869, 106, 56, 20, 1, 160, 10,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-61", {
+	1280, 1024, 1280, 1024, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 9090, 200, 48, 26, 1, 184, 3,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-85", {
+	1024, 768, 1024, 768, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 10111, 192, 32, 34, 14, 160, 6,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-70", {
+	1280, 1024, 1280, 1024, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 7905, 224, 32, 28, 8, 160, 8,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1152x864-84", {
+	1152, 864, 1152, 864, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 184, 312, 32, 0, 128, 12,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-76", {
+	1280, 1024, 1280, 1024, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 248, 32, 34, 3, 104, 3,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-85", {
+	1280, 1024, 1280, 1024, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 6349, 224, 64, 44, 1, 160, 3,
+	0,
+	FB_VMODE_NONINTERLACED
+    }},
 
-const unsigned long bt485_cursor_source[64] __initdata = {
-#if 1
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-#else
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-#endif
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
+    /* These are modes used by the two fixed-frequency monitors I have at home. 
+     * You may or may not find these useful.
+     */
 
-const unsigned int bt463_cursor_source[256] __initdata = {
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+    { "WYSE1", {			/* 1280x1024 @ 72 Hz, 130 Mhz clock */
+	1280, 1024, 1280, 1024, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 7692, 192, 32, 47, 0, 192, 5,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+	FB_VMODE_NONINTERLACED
+    }},
+    { "IBM3", {				/* 1280x1024 @ 70 Hz, 120 Mhz clock */
+	1280, 1024, 1280, 1024, 0, 0, 0, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCELF_TEXT, 8333, 192, 32, 47, 0, 192, 5,
+	0,
+	FB_VMODE_NONINTERLACED
+    }}
 };
 
-
-#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
-
-static int currcon = 0;
-static struct display disp;
-static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-#ifdef FBCON_HAS_CFB32
-static u32 fbcon_cfb32_cmap[16];
-#endif
-
-static struct fb_fix_screeninfo fb_fix = { { "DEC TGA ", } };
-static struct fb_var_screeninfo fb_var = { 0, };
+#define NUM_TOTAL_MODES    arraysize(tgafb_predefined)
 
 
     /*
      *  Interface used by the world
      */
 
+static void tgafb_detect(void);
+static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
+		        struct fb_info_gen *info);
+static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
+		        struct fb_info_gen *info);
+static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
+		        struct fb_info_gen *info);
+static void tgafb_get_par(void *fb_par, struct fb_info_gen *info);
+static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info);
+static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, 
+		u_int *transp, struct fb_info *info);
+static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
+		u_int transp, struct fb_info *info);
+static int tgafb_pan_display(const struct fb_var_screeninfo *var,
+		struct fb_info_gen *info);
+static int tgafb_blank(int blank, struct fb_info_gen *info);
+static void tgafb_set_disp(const void *fb_par, struct display *disp, 
+		struct fb_info_gen *info);
+
 static int tgafb_open(struct fb_info *info, int user);
 static int tgafb_release(struct fb_info *info, int user);
-static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int tgafb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int tgafb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int tgafb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *info);
-static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info);
-
-
-    /*
-     *  Interface to the low level console driver
-     */
-
+void tgafb_setup(char *options, int *ints);
 void tgafb_init(void);
-static int tgafbcon_switch(int con, struct fb_info *info);
-static int tgafbcon_updatevar(int con, struct fb_info *info);
-static void tgafbcon_blank(int blank, struct fb_info *info);
+void tgafb_cleanup(struct fb_info *info);
 
-
-    /*
-     *  Internal routines
-     */
-
-static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			   u_int *transp, struct fb_info *info);
-static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			   u_int transp, struct fb_info *info);
+static void tgafb_set_pll(int f);
 #if 1
-static void tga_update_palette(void);
+static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static void tgafb_update_palette(void);
 #endif
-static void do_install_cmap(int con, struct fb_info *info);
-
-
-static struct fb_ops tgafb_ops = {
-    tgafb_open, tgafb_release, tgafb_get_fix, tgafb_get_var, tgafb_set_var,
-    tgafb_get_cmap, tgafb_set_cmap, tgafb_pan_display, tgafb_ioctl
-};
 
 
     /*
-     *  Open/Release the frame buffer device
+     *  Chipset specific functions
      */
 
-static int tgafb_open(struct fb_info *info, int user)
-{
-    /*                                                                     
-     *  Nothing, only a usage count for the moment                          
-     */                                                                    
 
-    MOD_INC_USE_COUNT;
-    return(0);                              
-}
-        
-static int tgafb_release(struct fb_info *info, int user)
+static void tgafb_detect(void)
 {
-    MOD_DEC_USE_COUNT;
-    return(0);                                                    
+    return;
 }
 
 
-    /*
-     *  Get the Fixed Part of the Display
-     */
-
-static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
+	struct fb_info_gen *info)
 {
-    memcpy(fix, &fb_fix, sizeof(fb_fix));
-    return 0;
-}
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
+    strcpy(fix->id, fb_info.gen.info.modename);
 
-    /*
-     *  Get the User Defined Part of the Display
-     */
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
+    if (fb_info.tga_type == 0) /* 8-plane */
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+    else /* 24-plane or 24plusZ */
+	fix->visual = FB_VISUAL_TRUECOLOR;
+
+    fix->line_length = par->xres * (par->bits_per_pixel >> 3);
+    fix->smem_start = (char *)__pa(fb_info.tga_fb_base + dense_mem(fb_info.tga_fb_base));
+    fix->smem_len = fix->line_length * par->yres;
+    fix->mmio_start = (char *)__pa(fb_info.tga_regs_base);
+    fix->mmio_len = 0x1000;		/* Is this sufficient? */
+    fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0;
+    fix->accel = FB_ACCEL_DEC_TGA;
 
-static int tgafb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-    memcpy(var, &fb_var, sizeof(fb_var));
     return 0;
 }
 
 
-    /*
-     *  Set the User Defined Part of the Display
-     */
-
-static int tgafb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
+	struct fb_info_gen *info)
 {
-    struct display *display;
-    int oldbpp = -1, err;
-
-    if (con >= 0)
-	display = &fb_display[con];
-    else
-	display = &disp;	/* used during initialization */
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
-    if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
-	var->xres_virtual > fb_var.xres_virtual ||
-	var->yres_virtual > fb_var.yres_virtual ||
-	var->bits_per_pixel > fb_var.bits_per_pixel ||
-	var->nonstd ||
-	(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
-	return -EINVAL;
-    memcpy(var, &fb_var, sizeof(fb_var));
-
-    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-	oldbpp = display->var.bits_per_pixel;
-	display->var = *var;
-    }
-    if (oldbpp != var->bits_per_pixel) {
-	if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-	    return err;
-	do_install_cmap(con, info);
+    /* round up some */
+    if (fb_info.tga_type == 0) {
+	if (var->bits_per_pixel > 8) {
+	    return -EINVAL;
+	}
+	par->bits_per_pixel = 8;
+    } else {
+	if (var->bits_per_pixel > 32) {
+	    return -EINVAL;
+	}
+	par->bits_per_pixel = 32;
     }
-    return 0;
-}
 
-
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int tgafb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *info)
-{
-    if (var->xoffset || var->yoffset)
+    /* check the values for sanity */
+    if (var->xres_virtual != var->xres ||
+	var->yres_virtual != var->yres ||
+	var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ ||
+	(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED
+#if 0	
+	|| !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))
+#else
+	)
+#endif
 	return -EINVAL;
-    else
-	return 0;
-}
 
-    /*
-     *  Get the Colormap
-     */
+    /* encode video timings */
+    par->htimings = ((var->xres/4) & TGA_HORIZ_ACT_LSB) | 
+	(((var->xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB);
+    par->vtimings = (var->yres & TGA_VERT_ACTIVE);
+    par->htimings |= ((var->right_margin/4) << 9) & TGA_HORIZ_FP;
+    par->vtimings |= (var->lower_margin << 11) & TGA_VERT_FP;
+    par->htimings |= ((var->hsync_len/4) << 14) & TGA_HORIZ_SYNC;
+    par->vtimings |= (var->vsync_len << 16) & TGA_VERT_SYNC;
+    par->htimings |= ((var->left_margin/4) << 21) & TGA_HORIZ_BP;
+    par->vtimings |= (var->upper_margin << 22) & TGA_VERT_BP;
+
+    if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+	par->htimings |= TGA_HORIZ_POLARITY;
+    if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+	par->vtimings |= TGA_VERT_POLARITY;
+    /* what about sync on green? */
+
+    /* store other useful values in par */
+    par->xres = var->xres; 
+    par->yres = var->yres;
+    par->pll_freq = 1000000000/var->pixclock;
+    par->bits_per_pixel = var->bits_per_pixel;
 
-static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-    if (con == currcon) /* current console? */
-	return fb_get_cmap(cmap, kspc, tgafb_getcolreg, info);
-    else if (fb_display[con].cmap.len) /* non default colormap? */
-	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-    else
-	fb_copy_cmap(fb_default_cmap(256), cmap, kspc ? 0 : 2);
     return 0;
 }
 
-    /*
-     *  Set the Colormap
-     */
 
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
+	struct fb_info_gen *info)
 {
-    int err;
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
-    if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
-	if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0)))
-	    return err;
+    /* decode video timings */
+    var->xres = ((par->htimings & TGA_HORIZ_ACT_LSB) | ((par->htimings & TGA_HORIZ_ACT_MSB) >> 19)) * 4;
+    var->yres = (par->vtimings & TGA_VERT_ACTIVE);
+    var->right_margin = ((par->htimings & TGA_HORIZ_FP) >> 9) * 4;
+    var->lower_margin = ((par->vtimings & TGA_VERT_FP) >> 11);
+    var->hsync_len = ((par->htimings & TGA_HORIZ_SYNC) >> 14) * 4;
+    var->vsync_len = ((par->vtimings & TGA_VERT_SYNC) >> 16);
+    var->left_margin = ((par->htimings & TGA_HORIZ_BP) >> 21) * 4;
+    var->upper_margin = ((par->vtimings & TGA_VERT_BP) >> 22);
+
+    if (par->htimings & TGA_HORIZ_POLARITY) 
+    	var->sync |= FB_SYNC_HOR_HIGH_ACT;
+    if (par->vtimings & TGA_VERT_POLARITY)
+    	var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+    var->xres_virtual = var->xres;
+    var->yres_virtual = var->yres;
+    var->xoffset = var->yoffset = 0;
+
+    /* depth-related */
+    if (fb_info.tga_type == 0) {
+	var->red.offset = 0;
+	var->green.offset = 0;
+	var->blue.offset = 0;
+    } else {
+	/* XXX: is this correct? */
+	var->red.offset = 16;
+	var->green.offset = 8;
+	var->blue.offset = 0;
     }
-    if (con == currcon) {		/* current console? */
-	err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info);
-#if 1
-	if (tga_type != 0)
-		tga_update_palette();
-#endif
-	return err;
-    } else
-	fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+    var->bits_per_pixel = par->bits_per_pixel;
+    var->grayscale = 0;
+    var->red.length = var->green.length = var->blue.length = 8;
+    var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+
+    /* others */
+    var->xoffset = var->yoffset = 0;
+    var->pixclock = 1000000000/par->pll_freq;
+    var->nonstd = 0;
+    var->activate = 0;
+    var->height = var->width = -1;
+    var->accel_flags = 0;
+
     return 0;
 }
 
 
-static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info)
+static void tgafb_get_par(void *fb_par, struct fb_info_gen *info)
 {
-    return -EINVAL;
-}
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
+    if (current_par_valid)
+	*par = current_par;
+    else {
+	if (fb_info.tga_type == 0)
+	    default_var.bits_per_pixel = 8;
+	else
+	    default_var.bits_per_pixel = 32;
 
-    /*
-     *  Initialisation
-     */
+	tgafb_decode_var(&default_var, par, info);
+    }
+}
 
-__initfunc(void tgafb_init(void))
+
+static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info)
 {
     int i, j, temp;
-    unsigned char *cbp;
-    struct pci_dev *pdev;
-
-    pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
-    if (!pdev)
-	return;
-    tga_mem_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
-#ifdef DEBUG
-    printk("tgafb_init: mem_base 0x%x\n", tga_mem_base);
-#endif /* DEBUG */
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
-    tga_type = (readl((unsigned long)tga_mem_base) >> 12) & 0x0f;
-    switch (tga_type) {
-	case 0:
-	    strcat(fb_fix.id, "8plane");
-	    break;
-	case 1:
-	    strcat(fb_fix.id, "24plane");
-	    break;
-	case 3:
-	    strcat(fb_fix.id, "24plusZ");
-	    break;
-	default:
-	    printk("TGA type (0x%x) unrecognized!\n", tga_type);
+#if 0
+    /* XXX this will break console switching with X11, maybe I need to test KD_GRAPHICS? */
+    /* if current_par is valid, check to see if we need to change anything */
+    if (current_par_valid) {
+	if (!memcmp(par, &current_par, sizeof current_par)) {
 	    return;
+	}
     }
-
-    tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET);
-    tga_fb_base = ((unsigned long)tga_mem_base + fb_offset_presets[tga_type]);
+#endif
+    current_par = *par;
+    current_par_valid = 1;
 
     /* first, disable video timing */
     TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
-
+    
     /* write the DEEP register */
     while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
       continue;
 
     mb();
-    TGA_WRITE_REG(deep_presets[tga_type], TGA_DEEP_REG);
+    TGA_WRITE_REG(deep_presets[fb_info.tga_type], TGA_DEEP_REG);
     while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
 	continue;
     mb();
 
     /* write some more registers */
-    TGA_WRITE_REG(rasterop_presets[tga_type], TGA_RASTEROP_REG);
-    TGA_WRITE_REG(mode_presets[tga_type], TGA_MODE_REG);
-    TGA_WRITE_REG(base_addr_presets[tga_type], TGA_BASE_ADDR_REG);
-
-    /* write the PLL for 640x480 @ 60Hz */
-    for (i = 0; i <= 6; i++) {
-	for (j = 0; j <= 7; j++) {
-	    temp = (PLLbits[i] >> (7-j)) & 1;
-	    if (i == 6 && j == 7)
-		temp |= 2;
-	    TGA_WRITE_REG(temp, TGA_CLOCK_REG);
-	}
-    }
+    TGA_WRITE_REG(rasterop_presets[fb_info.tga_type], TGA_RASTEROP_REG);
+    TGA_WRITE_REG(mode_presets[fb_info.tga_type], TGA_MODE_REG);
+    TGA_WRITE_REG(base_addr_presets[fb_info.tga_type], TGA_BASE_ADDR_REG);
+
+    /* calculate & write the PLL */
+    tgafb_set_pll(par->pll_freq);
 
     /* write some more registers */
     TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG);
@@ -523,21 +507,19 @@
     TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG);
     TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG);
 
-    /* init video timing regs for 640x480 @ 60 Hz */
-    TGA_WRITE_REG(0x018608a0, TGA_HORIZ_REG);
-    TGA_WRITE_REG(0x084251e0, TGA_VERT_REG);
-
-    if (tga_type == 0) { /* 8-plane */
+    /* init video timing regs */
+    TGA_WRITE_REG(par->htimings, TGA_HORIZ_REG);
+    TGA_WRITE_REG(par->vtimings, TGA_VERT_REG);
 
-	fb_var.bits_per_pixel = 8;
-	fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
+    /* initalise RAMDAC */
+    if (fb_info.tga_type == 0) { /* 8-plane */
 
 	/* init BT485 RAMDAC registers */
 	BT485_WRITE(0xa2, BT485_CMD_0);
 	BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE);
 	BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */
 	BT485_WRITE(0x40, BT485_CMD_1);
-	BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */
+	BT485_WRITE(0x20, BT485_CMD_2); /* cursor off, for now */
 	BT485_WRITE(0xff, BT485_PIXEL_MASK);
 
 	/* fill palette registers */
@@ -560,6 +542,7 @@
 	    TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
 	}	  
 
+#if 0
 	/* initialize RAMDAC cursor colors */
 	BT485_WRITE(0, BT485_ADDR_CUR_WRITE);
 
@@ -581,19 +564,39 @@
 
 	/* initialize RAMDAC cursor RAM */
 	BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
-	cbp = (unsigned char *)bt485_cursor_source;
-	for (i = 0; i < 512; i++) {
-	    BT485_WRITE(*cbp++, BT485_CUR_RAM);
-	}
+
+	for (i = 0; i < tga_font_height_padded; i++)
+	    for (j = 7; j >= 0; j--) {
+#if 0
+		/* note that this is for a top-right alignment
+		 * - top left is commented out */
+		if( j > /*<*/ ((tga_font_width - 1) >> 3) ) {
+		    BT485_WRITE(0, BT485_CUR_RAM);
+		}
+		else if( j == ((tga_font_width - 1) >> 3) ) {
+		    BT485_WRITE((0xff >> /*<<*/
+				(7 - ((tga_font_width - 1)&7))) , BT485_CUR_RAM);
+		}
+		else {
+		    BT485_WRITE(0xff, BT485_CUR_RAM);
+		}
+#else
+		BT485_WRITE(0, BT485_CUR_RAM);
+#endif
+	    }
+	for (i = tga_font_height_padded; i < 64; i++)
+	    for (j = 0; j < 8; j++) {
+		BT485_WRITE(0, BT485_CUR_RAM);
+	    }
+	/* mask? */
+
 	for (i = 0; i < 512; i++) {
 	    BT485_WRITE(0xff, BT485_CUR_RAM);
 	}
+#endif
 
     } else { /* 24-plane or 24plusZ */
 
-	fb_var.bits_per_pixel = 32;
-	fb_fix.visual = FB_VISUAL_TRUECOLOR;
-
 	TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
 
 	/*
@@ -652,6 +655,7 @@
 	    TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
 	}
 
+#if 0
 	/*
 	 * init cursor colors
 	 */
@@ -679,135 +683,204 @@
 	temp = tga_fb_base - 1024; /* this assumes video starts at base
 				     and base is beyond memory start*/
 
-	for (i = 0; i < 256; i++) {
-	    writel(bt463_cursor_source[i], temp + i*4);
-	}
+	for (i = 0; i < tga_font_height_padded*4; i++)
+	    writel(bt463_cursor_source[i&3], temp + i*4);
+	for (i = tga_font_height_padded*4; i < 256; i++)
+	    writel(0, temp + i*4);
 	TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG);
+#endif
     }
 
     /* finally, enable video scan
-       (and pray for the monitor... :-) */
+	(and pray for the monitor... :-) */
     TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
+}
 
-    fb_var.xres = fb_var.xres_virtual = 640;
-    fb_var.yres = fb_var.yres_virtual = 480;
-    fb_fix.line_length = 80*fb_var.bits_per_pixel;
-    fb_fix.smem_start = (char *)__pa(tga_fb_base + dense_mem(tga_fb_base));
-    fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
-    fb_fix.type = FB_TYPE_PACKED_PIXELS;
-    fb_fix.type_aux = 0;
-    fb_fix.mmio_start = (char *)__pa(tga_regs_base);
-    fb_fix.mmio_len = 0x1000;		/* Is this sufficient? */
-    fb_fix.accel = FB_ACCEL_DEC_TGA;
-
-    fb_var.xoffset = fb_var.yoffset = 0;
-    fb_var.grayscale = 0;
-    if (tga_type == 0) { /* 8-plane */
-	fb_var.red.offset = 0;
-	fb_var.green.offset = 0;
-	fb_var.blue.offset = 0;
-    } else { /* 24-plane or 24plusZ */
-	/* XXX: is this correct?? */
-	fb_var.red.offset = 16;
-	fb_var.green.offset = 8;
-	fb_var.blue.offset = 0;
-    }
-    fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
-    fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
-    fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
-    fb_var.nonstd = 0;
-    fb_var.activate = 0;
-    fb_var.height = fb_var.width = -1;
-    fb_var.accel_flags = 0;
-    fb_var.pixclock = 39722;
-    fb_var.left_margin = 40;
-    fb_var.right_margin = 24;
-    fb_var.upper_margin = 32;
-    fb_var.lower_margin = 11;
-    fb_var.hsync_len = 96;
-    fb_var.vsync_len = 2;
-    fb_var.sync = 0;
-    fb_var.vmode = FB_VMODE_NONINTERLACED;
-
-    disp.var = fb_var;
-    disp.cmap.start = 0;
-    disp.cmap.len = 0;
-    disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
-    disp.screen_base = (char *)tga_fb_base + dense_mem(tga_fb_base);
-    disp.visual = fb_fix.visual;
-    disp.type = fb_fix.type;
-    disp.type_aux = fb_fix.type_aux;
-    disp.ypanstep = 0;
-    disp.ywrapstep = 0;
-    disp.line_length = fb_fix.line_length;
-    disp.can_soft_blank = 1;
-    disp.inverse = 0;
-    switch (tga_type) {
-#ifdef FBCON_HAS_CFB8
-	case 0: /* 8-plane */
-	    disp.dispsw = &fbcon_cfb8;
-	    break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 1: /* 24-plane */
-	case 3: /* 24plusZ */
-	    disp.dispsw = &fbcon_cfb32;
-	    disp.dispsw_data = &fbcon_cfb32_cmap;
-	    break;
-#endif
-	default:
-	    disp.dispsw = &fbcon_dummy;
+
+#define DIFFCHECK(x) { if( m <= 0x3f ) { \
+      int delta = f - (TGA_PLL_BASE_FREQ * (x)) / (r << shift); \
+      if (delta < 0) delta = -delta; \
+      if (delta < min_diff) min_diff = delta, vm = m, va = a, vr = r; } }
+
+static void tgafb_set_pll(int f)
+{
+    int                 n, shift, base, min_diff, target;
+    int                 r,a,m,vm = 34, va = 1, vr = 30;
+
+    for( r = 0 ; r < 12 ; r++ )
+	TGA_WRITE_REG(!r, TGA_CLOCK_REG);
+
+    if (f > TGA_PLL_MAX_FREQ)
+	f = TGA_PLL_MAX_FREQ;
+
+    if (f >= TGA_PLL_MAX_FREQ / 2)
+	shift = 0;
+    else if (f >= TGA_PLL_MAX_FREQ / 4)
+	shift = 1;
+    else
+	shift = 2;
+
+    TGA_WRITE_REG(shift & 1, TGA_CLOCK_REG);
+    TGA_WRITE_REG(shift >> 1, TGA_CLOCK_REG);
+
+    for( r = 0 ; r < 10 ; r++ ) {
+	TGA_WRITE_REG(0, TGA_CLOCK_REG);
     }
-    disp.scrollmode = SCROLL_YREDRAW;
 
-    strcpy(fb_info.modename, fb_fix.id);
-    fb_info.node = -1;
-    fb_info.fbops = &tgafb_ops;
-    fb_info.disp = &disp;
-    fb_info.fontname[0] = '\0';
-    fb_info.changevar = NULL;
-    fb_info.switch_con = &tgafbcon_switch;
-    fb_info.updatevar = &tgafbcon_updatevar;
-    fb_info.blank = &tgafbcon_blank;
-    fb_info.flags = FBINFO_FLAG_DEFAULT;
+    if (f <= 120000) {
+	TGA_WRITE_REG(0, TGA_CLOCK_REG);
+	TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    }
+    else if (f <= 200000) {
+	TGA_WRITE_REG(1, TGA_CLOCK_REG);
+	TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    }
+    else {
+	TGA_WRITE_REG(0, TGA_CLOCK_REG);
+	TGA_WRITE_REG(1, TGA_CLOCK_REG);
+    }
 
-    tgafb_set_var(&fb_var, -1, &fb_info);
+    TGA_WRITE_REG(1, TGA_CLOCK_REG);
+    TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    TGA_WRITE_REG(1, TGA_CLOCK_REG);
+    TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    TGA_WRITE_REG(1, TGA_CLOCK_REG);
+
+    target = (f << shift) / TGA_PLL_BASE_FREQ;
+    min_diff = TGA_PLL_MAX_FREQ;
+
+    r = 7 / target;
+    if (!r)
+	r = 1;
+
+    base = target * r;
+    while (base < 449) {
+	for (n = base < 7 ? 7 : base ; n < base + target && n < 449; n++) {
+	m = ((n + 3) / 7) - 1;
+	a = 0;
+	DIFFCHECK((m + 1) * 7);
+	m++;
+	DIFFCHECK((m + 1) * 7);
+	m = (n / 6) - 1;
+	if( (a = n % 6))
+	    DIFFCHECK( n );
+	}
+	r++;
+	base += target;
+    }
 
-    if (register_framebuffer(&fb_info) < 0)
-	return;
+    vr--;
 
-    printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
-	   fb_fix.id);
+    for( r=0; r<8 ; r++) {
+	TGA_WRITE_REG((vm >> r) & 1, TGA_CLOCK_REG);
+    }
+    for( r=0; r<8 ; r++) {
+	TGA_WRITE_REG((va >> r) & 1, TGA_CLOCK_REG);
+    }
+    for( r=0; r<7 ; r++) {
+	TGA_WRITE_REG((vr >> r) & 1, TGA_CLOCK_REG);
+    }
+    TGA_WRITE_REG(((vr >> 7) & 1)|2, TGA_CLOCK_REG);
 }
 
 
-static int tgafbcon_switch(int con, struct fb_info *info)
+static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp, struct fb_info *info)
 {
-    /* Do we have to save the colormap? */
-    if (fb_display[currcon].cmap.len)
-	fb_get_cmap(&fb_display[currcon].cmap, 1, tgafb_getcolreg, info);
+    if (regno > 255)
+	return 1;
+    *red = (palette[regno].red<<8) | palette[regno].red;
+    *green = (palette[regno].green<<8) | palette[regno].green;
+    *blue = (palette[regno].blue<<8) | palette[regno].blue;
+    *transp = 0;
+    return 0;
+}
+
+
+static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *info)
+{
+    if (regno > 255)
+	return 1;
+    red >>= 8;
+    green >>= 8;
+    blue >>= 8;
+    palette[regno].red = red;
+    palette[regno].green = green;
+    palette[regno].blue = blue;
+
+#ifdef FBCON_HAS_CFB32
+    if (regno < 16 && fb_info.tga_type != 0)
+	fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+#endif
+
+    if (fb_info.tga_type == 0) { /* 8-plane */
+        BT485_WRITE(regno, BT485_ADDR_PAL_WRITE);
+        TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+        TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+        TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+        TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+    }                                                    
+    /* How to set a single color register on 24-plane cards?? */
 
-    currcon = con;
-    /* Install new colormap */
-    do_install_cmap(con, info);
     return 0;
 }
 
+#if 1
     /*
-     *  Update the `var' structure (called by fbcon.c)
+     *	FIXME: since I don't know how to set a single arbitrary color register
+     *  on 24-plane cards, all color palette registers have to be updated
      */
 
-static int tgafbcon_updatevar(int con, struct fb_info *info)
+static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
 {
-    /* Nothing */
+    int err;
+
+    if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
+	if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0)))
+	    return err;
+    }
+    if (con == currcon) {		/* current console? */
+	err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info);
+#if 1
+	if (fb_info.tga_type != 0)
+		tgafb_update_palette();
+#endif
+	return err;
+    } else
+	fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
     return 0;
 }
 
-    /*
-     *  Blank and unblank the display.
-     */
+static void tgafb_update_palette(void)
+{
+    int i;
+
+    BT463_LOAD_ADDR(0x0000);
+    TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
+
+    for (i = 0; i < 256; i++) {
+	 TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+	 TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+	 TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+    }
+}
+#endif
+
+
+static int tgafb_pan_display(const struct fb_var_screeninfo *var, 
+	                             struct fb_info_gen *info)
+{
+    if (var->xoffset || var->yoffset)
+	return -EINVAL;
+    else
+	return 0;
+}
 
-static void tgafbcon_blank(int blank, struct fb_info *info)
+
+static int tgafb_blank(int blank, struct fb_info_gen *info)
 {
     static int tga_vesa_blanked = 0;
     u32 vhcr, vvcr;
@@ -854,158 +927,187 @@
     }
 
     restore_flags(flags);
-}
-
-    /*
-     *  Read a single color register and split it into
-     *  colors/transparent. Return != 0 for invalid regno.
-     */
-
-static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-    if (regno > 255)
-	return 1;
-    *red = (palette[regno].red<<8) | palette[regno].red;
-    *green = (palette[regno].green<<8) | palette[regno].green;
-    *blue = (palette[regno].blue<<8) | palette[regno].blue;
-    *transp = 0;
     return 0;
 }
 
 
-    /*
-     *  Set a single color register. The values supplied are already
-     *  rounded down to the hardware's capabilities (according to the
-     *  entries in the var structure). Return != 0 for invalid regno.
-     */
-
-static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
+static void tgafb_set_disp(const void *fb_par, struct display *disp,
+	struct fb_info_gen *info)
 {
-    if (regno > 255)
-	return 1;
-    red >>= 8;
-    green >>= 8;
-    blue >>= 8;
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-
+    disp->screen_base = (char *)fb_info.tga_fb_base + dense_mem(fb_info.tga_fb_base);
+    switch (fb_info.tga_type) {
+#ifdef FBCON_HAS_CFB8
+	case 0: /* 8-plane */
+	    disp->dispsw = &fbcon_cfb8;
+            break;
+#endif
 #ifdef FBCON_HAS_CFB32
-    if (regno < 16 && tga_type != 0)
-	fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+        case 1: /* 24-plane */
+        case 3: /* 24plusZ */
+            disp->dispsw = &fbcon_cfb32;
+            disp->dispsw_data = &fbcon_cfb32_cmap;
+            break;
 #endif
+        default:
+            disp->dispsw = &fbcon_dummy;
+    }
 
-    if (tga_type == 0) { /* 8-plane */
-        BT485_WRITE(regno, BT485_ADDR_PAL_WRITE);
-        TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
-        TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
-        TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
-        TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
-    }                                                    
-    /* How to set a single color register on 24-plane cards?? */
-
-    return 0;
+    disp->scrollmode = SCROLL_YREDRAW;
 }
 
 
-#if 1
+struct fbgen_hwswitch tgafb_hwswitch = {
+    tgafb_detect, tgafb_encode_fix, tgafb_decode_var, tgafb_encode_var, tgafb_get_par,
+    tgafb_set_par, tgafb_getcolreg, tgafb_setcolreg, tgafb_pan_display, tgafb_blank, 
+    tgafb_set_disp
+};
+
+
     /*
-     *	FIXME: since I don't know how to set a single arbitrary color register
-     *  on 24-plane cards, all color palette registers have to be updated
+     *  Hardware Independent functions
      */
 
-static void tga_update_palette(void)
-{
-    int i;
 
-    BT463_LOAD_ADDR(0x0000);
-    TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
+    /* 
+     *  Frame buffer operations
+     */
 
-    for (i = 0; i < 256; i++) {
-	 TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
-	 TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
-	 TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
-    }
+static int tgafb_open(struct fb_info *info, int user)
+{
+    MOD_INC_USE_COUNT;
+    return(0);                              
 }
-#endif
+      
 
-static void do_install_cmap(int con, struct fb_info *info)
+static int tgafb_release(struct fb_info *info, int user)
 {
-    if (con != currcon)
-	return;
-    if (fb_display[con].cmap.len)
-	fb_set_cmap(&fb_display[con].cmap, 1, tgafb_setcolreg, info);
-    else
-	fb_set_cmap(fb_default_cmap(256), 1, tgafb_setcolreg, info);
-#if 1
-    if (tga_type != 0)
-        tga_update_palette();
-#endif
+    MOD_DEC_USE_COUNT;
+    return(0);                                                    
 }
 
-#if 0	/* No cursor stuff yet */
 
-/*
- * Hide the cursor from view, during blanking, usually...
- */
-void
-hide_cursor(void)
-{
-	unsigned long flags;
-	save_flags(flags); cli();
+static struct fb_ops tgafb_ops = {
+    tgafb_open, tgafb_release, fbgen_get_fix, fbgen_get_var, fbgen_set_var,
+    fbgen_get_cmap, tgafb_set_cmap, fbgen_pan_display, fbgen_ioctl
+};
 
-	if (tga_type == 0) {
-	  BT485_WRITE(0x20, BT485_CMD_2);
-	} else {
-	  TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
-	}
 
-	restore_flags(flags);
+    /*
+     *  Setup
+     */
+
+__initfunc(void tgafb_setup(char *options, int *ints)) {
+    char *this_opt;
+    int i;
+    
+    if (options && *options)
+    	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+       	    if (!*this_opt) continue;
+        
+	    if (!strncmp(this_opt, "font:", 5))
+	     	strncpy(default_fontname, this_opt+5, sizeof default_fontname);
+	    else if (!strncmp(this_opt, "mode:", 5)) {
+    		for (i = 0; i < NUM_TOTAL_MODES; i++) {
+    		    if (!strcmp(this_opt+5, tgafb_predefined[i].name))
+    			default_var = tgafb_predefined[i].var;
+		    	default_var_valid = 1;
+    		}
+    	    } else {
+      		printk(KERN_ERR "tgafb: unknown parameter %s\n", this_opt);
+    	    }
+      	}
 }
 
-void
-set_cursor(int currcons)
+
+    /*
+     *  Initialisation
+     */
+
+__initfunc(void tgafb_init(void))
 {
-  unsigned int idx, xt, yt, row, col;
-  unsigned long flags;
+    struct pci_dev *pdev;
 
-  if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
-    return;
+    pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
+    if (!pdev)
+	return;
+    fb_info.tga_mem_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+#ifdef DEBUG
+    printk("tgafb_init: mem_base 0x%x\n", fb_info.tga_mem_base);
+#endif /* DEBUG */
+
+    fb_info.tga_type = (readl((unsigned long)fb_info.tga_mem_base) >> 12) & 0x0f;
+    fb_info.tga_regs_base = ((unsigned long)fb_info.tga_mem_base + TGA_REGS_OFFSET);
+    fb_info.tga_fb_base = ((unsigned long)fb_info.tga_mem_base + fb_offset_presets[fb_info.tga_type]);
+
+    /* XXX Why the fuck is it called modename if it identifies the board? */
+    strcpy (fb_info.gen.info.modename,"DEC 21030 TGA "); 
+    switch (fb_info.tga_type) 
+    { 
+	case 0: /* 8-plane */
+	    strcat (fb_info.gen.info.modename, "8-plane");
+	    break;
 
-  save_flags(flags); cli();
+	case 1:
+	    strcat (fb_info.gen.info.modename, "24-plane");
+	    break;
 
-  if (deccm) {
-    idx = (pos - video_mem_base) >> 1;
-    col = idx % 80;
-    row = (idx - col) / 80;
+	case 3:
+	    strcat (fb_info.gen.info.modename, "24plusZ");
+	    break;
+    }
 
-    if (tga_type == 0) { /* 8-plane */
+    fb_info.gen.info.node = -1;
+    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+    fb_info.gen.info.fbops = &tgafb_ops;
+    fb_info.gen.info.disp = &disp;
+    fb_info.gen.info.changevar = NULL;
+    fb_info.gen.info.switch_con = &fbgen_switch;
+    fb_info.gen.info.updatevar = &fbgen_update_var;
+    fb_info.gen.info.blank = &fbgen_blank;
+    strcpy(fb_info.gen.info.fontname, default_fontname);
+    fb_info.gen.parsize = sizeof (struct tgafb_par);
+    fb_info.gen.fbhw = &tgafb_hwswitch;
+    fb_info.gen.fbhw->detect();
+
+    /* This should give a reasonable default video mode */
+    if (!default_var_valid)
+	default_var = tgafb_predefined[0].var;
+    fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+    disp.var.activate = FB_ACTIVATE_NOW;
+    fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+    fbgen_set_disp(-1, &fb_info.gen);
+    fbgen_install_cmap(0, &fb_info.gen);
+    if (register_framebuffer(&fb_info.gen.info) < 0)
+	return;
+    printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
+	fb_info.gen.info.modename);
+}
 
-      xt = col * TGA_F_WIDTH + 64;
-      yt = row * TGA_F_HEIGHT_PADDED + 64;
 
-      /* make sure it's enabled */
-      BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */
+    /*
+     *  Cleanup
+     */
 
-      BT485_WRITE(xt, BT485_CUR_LOW_X);
-      BT485_WRITE((xt >> 8), BT485_CUR_HIGH_X);
-      BT485_WRITE(yt, BT485_CUR_LOW_Y);
-      BT485_WRITE((yt >> 8), BT485_CUR_HIGH_Y);
+void tgafb_cleanup(struct fb_info *info)
+{
+    unregister_framebuffer(info);
+}
 
-    } else {
 
-      xt = col * TGA_F_WIDTH + 144;
-      yt = row * TGA_F_HEIGHT_PADDED + 35;
+    /*
+     *  Modularisation
+     */
 
-      TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */
-      TGA_WRITE_REG(xt | (yt << 12), TGA_CURSOR_XY_REG);
-    }
+#ifdef MODULE
+int init_module(void)
+{
+    tgafb_init();
+    return 0;
+}
 
-  } else
-    hide_cursor();
-  restore_flags(flags);
+void cleanup_module(void)
+{
+    tgafb_cleanup(void);
 }
+#endif /* MODULE */
 
-#endif
diff -u --recursive --new-file v2.3.9/linux/drivers/video/tgafb.h linux/drivers/video/tgafb.h
--- v2.3.9/linux/drivers/video/tgafb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/tgafb.h	Thu Jul  1 10:57:36 1999
@@ -0,0 +1,190 @@
+/*
+ *  linux/drivers/video/tgafb.h -- DEC 21030 TGA frame buffer device
+ *
+ *  	Copyright (C) 1999 Martin Lucina, Tom Zerucha
+ *  
+ *  $Id: tgafb.h,v 1.4 1999/05/15 08:44:31 mato Exp $
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef TGAFB_H
+#define TGAFB_H
+
+    /*
+     * TGA hardware description (minimal)
+     */
+
+
+    /*
+     * Offsets within Memory Space
+     */
+
+#define	TGA_ROM_OFFSET			0x0000000
+#define	TGA_REGS_OFFSET			0x0100000
+#define	TGA_8PLANE_FB_OFFSET		0x0200000
+#define	TGA_24PLANE_FB_OFFSET		0x0804000
+#define	TGA_24PLUSZ_FB_OFFSET		0x1004000
+
+#define	TGA_PLANEMASK_REG		0x0028
+#define	TGA_MODE_REG			0x0030
+#define	TGA_RASTEROP_REG		0x0034
+#define	TGA_PIXELSHIFT_REG		0x0038
+#define	TGA_DEEP_REG			0x0050
+#define	TGA_PIXELMASK_REG		0x005c
+#define	TGA_CURSOR_BASE_REG		0x0060
+#define	TGA_HORIZ_REG			0x0064
+#define	TGA_VERT_REG			0x0068
+#define	TGA_BASE_ADDR_REG		0x006c
+#define	TGA_VALID_REG			0x0070
+#define	TGA_CURSOR_XY_REG		0x0074
+#define	TGA_INTR_STAT_REG		0x007c
+#define	TGA_RAMDAC_SETUP_REG		0x00c0
+#define	TGA_BLOCK_COLOR0_REG		0x0140
+#define	TGA_BLOCK_COLOR1_REG		0x0144
+#define	TGA_CLOCK_REG			0x01e8
+#define	TGA_RAMDAC_REG			0x01f0
+#define	TGA_CMD_STAT_REG		0x01f8
+
+
+    /* 
+     * useful defines for managing the video timing registers
+     */
+
+#define TGA_HORIZ_ODD			0x80000000
+#define TGA_HORIZ_POLARITY		0x40000000
+#define TGA_HORIZ_ACT_MSB		0x30000000
+#define TGA_HORIZ_BP			0x0fe00000
+#define TGA_HORIZ_SYNC			0x001fc000
+#define TGA_HORIZ_FP			0x00007c00
+#define TGA_HORIZ_ACT_LSB		0x000001ff
+
+#define TGA_VERT_SE			0x80000000
+#define TGA_VERT_POLARITY		0x40000000
+#define TGA_VERT_RESERVED		0x30000000
+#define TGA_VERT_BP			0x0fc00000
+#define TGA_VERT_SYNC			0x003f0000
+#define TGA_VERT_FP			0x0000f800
+#define TGA_VERT_ACTIVE			0x000007ff
+
+
+    /*
+     * useful defines for managing the ICS1562 PLL clock
+     */
+
+#define TGA_PLL_BASE_FREQ 		14318		/* .18 */
+#define TGA_PLL_MAX_FREQ 		230000
+
+
+    /*
+     * useful defines for managing the BT485 on the 8-plane TGA
+     */
+
+#define	BT485_READ_BIT			0x01
+#define	BT485_WRITE_BIT			0x00
+
+#define	BT485_ADDR_PAL_WRITE		0x00
+#define	BT485_DATA_PAL			0x02
+#define	BT485_PIXEL_MASK		0x04
+#define	BT485_ADDR_PAL_READ		0x06
+#define	BT485_ADDR_CUR_WRITE		0x08
+#define	BT485_DATA_CUR			0x0a
+#define	BT485_CMD_0			0x0c
+#define	BT485_ADDR_CUR_READ		0x0e
+#define	BT485_CMD_1			0x10
+#define	BT485_CMD_2			0x12
+#define	BT485_STATUS			0x14
+#define	BT485_CMD_3			0x14
+#define	BT485_CUR_RAM			0x16
+#define	BT485_CUR_LOW_X			0x18
+#define	BT485_CUR_HIGH_X		0x1a
+#define	BT485_CUR_LOW_Y			0x1c
+#define	BT485_CUR_HIGH_Y		0x1e
+
+
+    /*
+     * useful defines for managing the BT463 on the 24-plane TGAs
+     */
+
+#define	BT463_ADDR_LO		0x0
+#define	BT463_ADDR_HI		0x1
+#define	BT463_REG_ACC		0x2
+#define	BT463_PALETTE		0x3
+
+#define	BT463_CUR_CLR_0		0x0100
+#define	BT463_CUR_CLR_1		0x0101
+
+#define	BT463_CMD_REG_0		0x0201
+#define	BT463_CMD_REG_1		0x0202
+#define	BT463_CMD_REG_2		0x0203
+
+#define	BT463_READ_MASK_0	0x0205
+#define	BT463_READ_MASK_1	0x0206
+#define	BT463_READ_MASK_2	0x0207
+#define	BT463_READ_MASK_3	0x0208
+
+#define	BT463_BLINK_MASK_0	0x0209
+#define	BT463_BLINK_MASK_1	0x020a
+#define	BT463_BLINK_MASK_2	0x020b
+#define	BT463_BLINK_MASK_3	0x020c
+
+#define	BT463_WINDOW_TYPE_BASE	0x0300
+
+
+    /*
+     * Macros for reading/writing TGA and RAMDAC registers
+     */
+
+#define TGA_WRITE_REG(v,r) \
+	{ writel((v), fb_info.tga_regs_base+(r)); mb(); }
+
+#define TGA_READ_REG(r) readl(fb_info.tga_regs_base+(r))
+
+#define BT485_WRITE(v,r) \
+	  TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG);		\
+	  TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
+
+#define BT463_LOAD_ADDR(a) \
+	TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
+	TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
+	TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
+	TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
+
+#define BT463_WRITE(m,a,v) \
+	BT463_LOAD_ADDR((a)); \
+	TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
+	TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
+
+
+    /*
+     *  This structure describes the board.
+     */
+
+struct tgafb_info {
+    /* Use the generic framebuffer ops */
+    struct fb_info_gen gen;
+
+    /* Device dependent information */
+    int tga_type;					/* TGA type: {8plane, 24plane, 24plusZ} */
+    unsigned int tga_mem_base;
+    unsigned long tga_fb_base;
+    unsigned long tga_regs_base;
+    struct fb_var_screeninfo default_var;		/* default video mode */
+};
+
+
+    /*
+     *  This structure uniquely defines a video mode.
+     */
+
+struct tgafb_par {
+    int xres, yres;					/* resolution in pixels */
+    unsigned int htimings;				/* horizontal timing register */
+    unsigned int vtimings;				/* vertical timing register */
+    unsigned int pll_freq;				/* pixclock in mhz */
+    unsigned int bits_per_pixel;			/* bits per pixel */
+};
+
+#endif /* TGAFB_H */
diff -u --recursive --new-file v2.3.9/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.9/linux/fs/binfmt_aout.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/binfmt_aout.c	Thu Jul  1 10:45:57 1999
@@ -461,7 +461,8 @@
 		return retval;
 	}
 
-	current->mm->start_stack = create_aout_tables(bprm->p, bprm);
+	current->mm->start_stack =
+		(unsigned long) create_aout_tables((char *) bprm->p, bprm);
 #ifdef __alpha__
 	regs->gp = ex.a_gpvalue;
 #endif
diff -u --recursive --new-file v2.3.9/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.9/linux/fs/binfmt_elf.c	Fri Jun 18 08:01:10 1999
+++ linux/fs/binfmt_elf.c	Mon Jul  5 19:59:55 1999
@@ -443,6 +443,8 @@
 
 	retval = -ENOMEM;
 	size = elf_ex.e_phentsize * elf_ex.e_phnum;
+	if (size > 65536)
+		goto out;
 	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 	if (!elf_phdata)
 		goto out;
diff -u --recursive --new-file v2.3.9/linux/fs/coda/cache.c linux/fs/coda/cache.c
--- v2.3.9/linux/fs/coda/cache.c	Fri Dec 18 12:45:00 1998
+++ linux/fs/coda/cache.c	Tue Jul  6 19:08:33 1999
@@ -326,8 +326,8 @@
 	while ( alias != &inode->i_dentry ) {
 		alias_de = list_entry(alias, struct dentry, d_alias);
 		coda_flag_children(alias_de, flag);
-		shrink_dcache_parent(alias_de);
 		alias = alias->next;
+		shrink_dcache_parent(alias_de);
 	}
 
 }
diff -u --recursive --new-file v2.3.9/linux/fs/coda/cnode.c linux/fs/coda/cnode.c
--- v2.3.9/linux/fs/coda/cnode.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/coda/cnode.c	Tue Jul  6 19:08:33 1999
@@ -14,6 +14,17 @@
 extern int coda_debug;
 extern int coda_print_entry;
 
+inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
+{
+	if (fid1->Vnode != fid2->Vnode)
+		return 0;
+	if (fid1->Volume != fid2->Volume)
+		return 0;
+	if (fid1->Unique != fid2->Unique)
+		return 0;
+	return 1;
+}
+
 /* cnode.c */
 static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
 {
@@ -71,8 +82,14 @@
         }
 
 	cnp = ITOC(*inode);
-       if  ( cnp->c_magic != 0 ) {
-               printk("coda_cnode make on initialized inode %ld, old %s new
+	/* see if we've got it already */
+	if  ( cnp->c_magic != 0 && coda_fideq(fid, &cnp->c_fid)) {
+		return 0;
+	}
+
+	/* not fresh: collision */
+	if  ( cnp->c_magic != 0 ) {
+               printk("coda_cnode_make on initialized inode %ld, old %s new
 %s!\n",
                       (*inode)->i_ino, coda_f2s(&cnp->c_fid), coda_f2s2(fid));
                iput(*inode);
@@ -106,14 +123,6 @@
         return 0;
 }
 
-inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
-{
-	int eq;
-	eq =   ( (fid1->Vnode == fid2->Vnode) &&
-		 (fid1->Volume == fid2->Volume) &&
-		 (fid1->Unique == fid2->Unique) );
-	return eq;
-}
 
 void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid, 
 		      struct ViceFid *newfid)
diff -u --recursive --new-file v2.3.9/linux/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c
--- v2.3.9/linux/fs/coda/coda_linux.c	Mon Jan 25 10:28:35 1999
+++ linux/fs/coda/coda_linux.c	Tue Jul  6 19:08:33 1999
@@ -215,6 +215,8 @@
         if (attr->va_ctime.tv_sec != -1)
 	        inode->i_ctime = attr->va_ctime.tv_sec;
 }
+
+
 /* 
  * BSD sets attributes that need not be modified to -1. 
  * Linux uses the valid field to indicate what should be
diff -u --recursive --new-file v2.3.9/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.3.9/linux/fs/coda/dir.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/coda/dir.c	Tue Jul  6 19:08:33 1999
@@ -800,16 +800,16 @@
 
 	shrink_dcache_parent(de);
 
+	/* propagate for a flush */
+	if (cii->c_flags & C_FLUSH) 
+		coda_flag_inode_children(inode, C_FLUSH);
+
 	if (de->d_count > 1) {
 		/* pretend it's valid, but don't change the flags */
 		CDEBUG(D_DOWNCALL, "BOOM for: ino %ld, %s\n",
 		       de->d_inode->i_ino, coda_f2s(&cii->c_fid));
 		return 1;
 	}
-
-	/* propagate for a flush */
-	if (cii->c_flags & C_FLUSH) 
-		coda_flag_inode_children(inode, C_FLUSH);
 
 	/* clear the flags. */
 	cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
diff -u --recursive --new-file v2.3.9/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.3.9/linux/fs/coda/inode.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/coda/inode.c	Tue Jul  6 19:08:33 1999
@@ -22,8 +22,6 @@
 #include <asm/uaccess.h>
 
 #include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
 #include <linux/vmalloc.h>
 #include <asm/segment.h>
 
@@ -75,6 +73,9 @@
 
         if ( sbi->sbi_sb ) {
 		printk("Already mounted\n");
+		unlock_super(sb);
+		EXIT;  
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
@@ -98,7 +99,6 @@
 	        printk("coda_read_super: coda_get_rootfid failed with %d\n",
 		       error);
 		sb->s_dev = 0;
-	        unlock_super(sb);
 		goto error;
 	}	  
 	printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
@@ -108,7 +108,6 @@
         if ( error || !root ) {
 	    printk("Failure of coda_cnode_make for root: error %d\n", error);
 	    sb->s_dev = 0;
-	    unlock_super(sb);
 	    goto error;
 	} 
 
@@ -121,6 +120,7 @@
         return sb;
 
  error:
+	unlock_super(sb);
 	EXIT;  
 	MOD_DEC_USE_COUNT;
 	if (sbi) {
@@ -145,7 +145,6 @@
         sb->s_dev = 0;
 	coda_cache_clear_all(sb);
 	sb_info = coda_sbp(sb);
-/*	sb_info->sbi_vcomm->vc_inuse = 0; You can not do this: psdev_release would see usagecount == 0 and would refuse to decrease MOD_USE_COUNT --pavel */ 
 	coda_super_info.sbi_sb = NULL;
 	printk("Coda: Bye bye.\n");
 	memset(sb_info, 0, sizeof(* sb_info));
@@ -209,7 +208,7 @@
 	EXIT;
 }
 
-static int  coda_notify_change(struct dentry *de, struct iattr *iattr)
+static int coda_notify_change(struct dentry *de, struct iattr *iattr)
 {
 	struct inode *inode = de->d_inode;
         struct coda_inode_info *cii;
@@ -238,21 +237,32 @@
         return error;
 }
 
-/*  we need _something_ for this routine. Let's mimic AFS */
 static int coda_statfs(struct super_block *sb, struct statfs *buf, 
 		       int bufsiz)
 {
 	struct statfs tmp;
+	int error;
+
+	memset(&tmp, 0, sizeof(struct statfs));
 
+	error = venus_statfs(sb, &tmp);
+
+	if (error) {
+		/* fake something like AFS does */
+		tmp.f_blocks = 9000000;
+		tmp.f_bfree  = 9000000;
+		tmp.f_bavail = 9000000;
+		tmp.f_files  = 9000000;
+		tmp.f_ffree  = 9000000;
+	}
+
+	/* and fill in the rest */
 	tmp.f_type = CODA_SUPER_MAGIC;
 	tmp.f_bsize = 1024;
-	tmp.f_blocks = 9000000;
-	tmp.f_bfree = 9000000;
-	tmp.f_bavail = 9000000 ;
-	tmp.f_files = 9000000;
-	tmp.f_ffree = 9000000;
-	tmp.f_namelen = 0;
+	tmp.f_namelen = CODA_MAXNAMLEN;
+
 	copy_to_user(buf, &tmp, bufsiz);
+
 	return 0; 
 }
 
diff -u --recursive --new-file v2.3.9/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c
--- v2.3.9/linux/fs/coda/sysctl.c	Sat Feb  6 12:46:21 1999
+++ linux/fs/coda/sysctl.c	Tue Jul  6 19:08:33 1999
@@ -71,6 +71,7 @@
 struct coda_cache_inv_stats	coda_cache_inv_stat;
 struct coda_upcall_stats_entry  coda_upcall_stat[CODA_NCALLS];
 struct coda_upcallstats         coda_callstats;
+int                             coda_upcall_timestamping = 0;
 
 /* keep this in sync with coda.h! */
 char *coda_upcall_names[] = {
@@ -103,9 +104,12 @@
 	"purgeuser   ",   /* 26 */
 	"zapfile     ",   /* 27 */
 	"zapdir      ",   /* 28 */
-	"zapvnode    ",   /* 28 */
+	"noop2       ",   /* 29 */
 	"purgefid    ",   /* 30 */
-	"open_by_path"    /* 31 */
+	"open_by_path",   /* 31 */
+	"resolve     ",   /* 32 */
+	"reintegrate ",   /* 33 */
+	"statfs      "    /* 34 */
 };
 
 
@@ -133,8 +137,7 @@
 void do_time_stats( struct coda_upcall_stats_entry * pentry, 
 		    unsigned long runtime )
 {
-	
-	unsigned long time = runtime * 1000 /HZ;	/* time in ms */
+	unsigned long time = runtime;	/* time in us */
 	CDEBUG(D_SPECIAL, "time: %ld\n", time);
 
 	if ( pentry->count == 0 ) {
@@ -221,9 +224,12 @@
 {
 	if ( write ) {
 		reset_coda_vfs_stats();
+
+		filp->f_pos += *lenp;
+	} else {
+		*lenp = 0;
 	}
-  
-	*lenp = 0;
+
 	return 0;
 }
 
@@ -232,10 +238,19 @@
 				size_t * lenp )
 {
 	if ( write ) {
+        	if (*lenp > 0) {
+			char c;
+                	if (get_user(c, (char *)buffer))
+			       	return -EFAULT;
+                        coda_upcall_timestamping = (c == '1');
+                }
 		reset_coda_upcall_stats();
+
+		filp->f_pos += *lenp;
+	} else {
+		*lenp = 0;
 	}
-  
-	*lenp = 0;
+
 	return 0;
 }
 
@@ -245,9 +260,12 @@
 {
 	if ( write ) {
 		reset_coda_permission_stats();
+
+		filp->f_pos += *lenp;
+	} else {
+		*lenp = 0;
 	}
-  
-	*lenp = 0;
+
 	return 0;
 }
 
@@ -257,9 +275,12 @@
 {
 	if ( write ) {
 		reset_coda_cache_inv_stats();
+
+		filp->f_pos += *lenp;
+	} else {
+		*lenp = 0;
 	}
   
-	*lenp = 0;
 	return 0;
 }
 
@@ -347,12 +368,12 @@
 	if ( offset < 160) 
 		len += sprintf( buffer + len,"%-79s\n",	"======================");
 	if ( offset < 240) 
-		len += sprintf( buffer + len,"%-79s\n",	"upcall\t\t    count\tavg time(ms)\tstd deviation(ms)");
+		len += sprintf( buffer + len,"%-79s\n",	"upcall              count       avg time(us)    std deviation(us)");
 	if ( offset < 320) 
-		len += sprintf( buffer + len,"%-79s\n",	"------\t\t    -----\t------------\t-----------------");
+		len += sprintf( buffer + len,"%-79s\n",	"------              -----       ------------    -----------------");
 	pos = 320; 
 	for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
-		tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld", 
+		tmplen += sprintf(tmpbuf,"%s    %9d       %10ld      %10ld", 
 				  coda_upcall_names[i],
 				  coda_upcall_stat[i].count, 
 				  get_time_average(&coda_upcall_stat[i]),
@@ -499,6 +520,7 @@
 		MOD_INC_USE_COUNT;
 	else
 		MOD_DEC_USE_COUNT;
+			
 }
 
 #endif
diff -u --recursive --new-file v2.3.9/linux/fs/coda/upcall.c linux/fs/coda/upcall.c
--- v2.3.9/linux/fs/coda/upcall.c	Tue May 11 23:04:59 1999
+++ linux/fs/coda/upcall.c	Tue Jul  6 19:08:33 1999
@@ -580,6 +580,33 @@
 	return error;
 }
 
+int venus_statfs(struct super_block *sb, struct statfs *sfs) 
+{ 
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        
+	insize = max(INSIZE(statfs), OUTSIZE(statfs));
+	UPARG(CODA_STATFS);
+
+        error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+	
+        if (!error) {
+		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
+		sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
+		sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
+		sfs->f_files  = outp->coda_statfs.stat.f_files;
+		sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
+	} else {
+		printk("coda_statfs: Venus returns: %d\n", error);
+	}
+
+        if (inp) CODA_FREE(inp, insize);
+        CDEBUG(D_INODE, " result %d\n",error);
+        EXIT;
+        return error;
+}
+
 /*
  * coda_upcall and coda_downcall routines.
  * 
@@ -588,10 +615,12 @@
 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	unsigned long posttime;
+ 	struct timeval begin = { 0, 0 }, end = { 0, 0 };
 
 	vmp->uc_posttime = jiffies;
-	posttime = jiffies;
+
+	if (coda_upcall_timestamping)
+		do_gettimeofday(&begin);
 
 	add_wait_queue(&vmp->uc_sleep, &wait);
 	for (;;) {
@@ -620,9 +649,20 @@
 	remove_wait_queue(&vmp->uc_sleep, &wait);
 	current->state = TASK_RUNNING;
 
-	CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime);
-	return 	(jiffies - posttime);
+	if (coda_upcall_timestamping && begin.tv_sec != 0) {
+		do_gettimeofday(&end);
+
+		if (end.tv_usec < begin.tv_usec) {
+			end.tv_usec += 1000000; end.tv_sec--;
+		}
+		end.tv_sec  -= begin.tv_sec;
+		end.tv_usec -= begin.tv_usec;
+	}
+
+	CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
+		begin.tv_sec, begin.tv_usec, end.tv_sec, end.tv_usec);
 
+	return 	((end.tv_sec * 1000000) + end.tv_usec);
 }
 
 
diff -u --recursive --new-file v2.3.9/linux/fs/devices.c linux/fs/devices.c
--- v2.3.9/linux/fs/devices.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/devices.c	Sun Jul  4 10:02:30 1999
@@ -277,6 +277,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
@@ -333,6 +334,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
diff -u --recursive --new-file v2.3.9/linux/fs/dquot.c linux/fs/dquot.c
--- v2.3.9/linux/fs/dquot.c	Thu May 13 14:31:27 1999
+++ linux/fs/dquot.c	Sat Jul  3 10:42:21 1999
@@ -577,32 +577,35 @@
 static void add_dquot_ref(kdev_t dev, short type)
 {
 	struct super_block *sb = get_super(dev);
-	struct file *filp;
+	struct list_head *p;
 	struct inode *inode;
 
 	if (!sb || !sb->dq_op)
 		return;	/* nothing to do */
 
-	for (filp = inuse_filps; filp; filp = filp->f_next) {
+	file_list_lock();
+	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+		struct file *filp = list_entry(p, struct file, f_list);
 		if (!filp->f_dentry)
 			continue;
-		if (filp->f_dentry->d_sb != sb)
-			continue;
 		inode = filp->f_dentry->d_inode;
 		if (!inode)
 			continue;
 		/* N.B. race problem -- filp could become unused */
 		if (filp->f_mode & FMODE_WRITE) {
+			file_list_unlock();
 			sb->dq_op->initialize(inode, type);
 			inode->i_flags |= S_QUOTA;
+			file_list_lock();
 		}
 	}
+	file_list_unlock();
 }
 
 static void reset_dquot_ptrs(kdev_t dev, short type)
 {
 	struct super_block *sb = get_super(dev);
-	struct file *filp;
+	struct list_head *p;
 	struct inode *inode;
 	struct dquot *dquot;
 	int cnt;
@@ -614,11 +617,11 @@
 	/* free any quota for unused dentries */
 	shrink_dcache_sb(sb);
 
-	for (filp = inuse_filps; filp; filp = filp->f_next) {
+	file_list_lock();
+	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+		struct file *filp = list_entry(p, struct file, f_list);
 		if (!filp->f_dentry)
 			continue;
-		if (filp->f_dentry->d_sb != sb)
-			continue;
 		inode = filp->f_dentry->d_inode;
 		if (!inode)
 			continue;
@@ -637,12 +640,14 @@
 			inode->i_flags &= ~S_QUOTA;
 		put_it:
 			if (dquot != NODQUOT) {
+				file_list_unlock();
 				dqput(dquot);
 				/* we may have blocked ... */
 				goto restart;
 			}
 		}
 	}
+	file_list_unlock();
 }
 
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
diff -u --recursive --new-file v2.3.9/linux/fs/exec.c linux/fs/exec.c
--- v2.3.9/linux/fs/exec.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/exec.c	Mon Jul  5 20:34:31 1999
@@ -119,8 +119,12 @@
 {
 	struct inode * inode = dentry->d_inode;
 	struct file * f;
+	struct list_head * l = NULL;
 	int fd, error;
 
+	if (inode->i_sb)
+		l = &inode->i_sb->s_files;
+
 	error = -EINVAL;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto out;
@@ -141,6 +145,7 @@
 			if (error)
 				goto out_filp;
 		}
+		file_move(f, l);
 		fd_install(fd, f);
 		dget(dentry);
 	}
@@ -465,8 +470,7 @@
 		i = j * __NFDBITS;
 		if (i >= files->max_fds)
 			break;
-		set = files->close_on_exec.fds_bits[j];
-		files->close_on_exec.fds_bits[j] = 0;
+		set = xchg(&files->close_on_exec.fds_bits[j], 0);
 		j++;
 		for ( ; set ; i++,set >>= 1) {
 			if (set & 1)
@@ -559,7 +563,7 @@
 	if ((retval = permission(inode, MAY_EXEC)) != 0)
 		return retval;
 	/* better not execute files which are being written to */
-	if (inode->i_writecount > 0)
+	if (atomic_read(&inode->i_writecount) > 0)
 		return -ETXTBSY;
 
 	bprm->e_uid = current->euid;
diff -u --recursive --new-file v2.3.9/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c
--- v2.3.9/linux/fs/ext2/ioctl.c	Tue May 11 14:37:47 1999
+++ linux/fs/ext2/ioctl.c	Thu Jul  1 16:04:08 1999
@@ -27,28 +27,35 @@
 	case EXT2_IOC_GETFLAGS:
 		flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
 		return put_user(inode->u.ext2_i.i_flags, (int *) arg);
-	case EXT2_IOC_SETFLAGS:
+	case EXT2_IOC_SETFLAGS: {
+		unsigned int oldflags;
+
+		if (IS_RDONLY(inode))
+			return -EROFS;
+
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EPERM;
+
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
-		flags = flags & EXT2_FL_USER_MODIFIABLE;
+
+		oldflags = inode->u.ext2_i.i_flags;
+
 		/*
 		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-		 * the super user when the security level is zero.
+		 * the relevant capability.
+		 *
+		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
-		if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^
-		    (inode->u.ext2_i.i_flags &
-		     (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
-			/* This test looks nicer. Thanks to Pauline Middelink */
+		if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
 			if (!capable(CAP_LINUX_IMMUTABLE))
 				return -EPERM;
-		} else
-			if ((current->fsuid != inode->i_uid) && 
-			    !capable(CAP_FOWNER))
-				return -EPERM;
-		if (IS_RDONLY(inode))
-			return -EROFS;
-		inode->u.ext2_i.i_flags = (inode->u.ext2_i.i_flags &
-					   ~EXT2_FL_USER_MODIFIABLE) | flags;
+		}
+
+		flags = flags & EXT2_FL_USER_MODIFIABLE;
+		flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
+		inode->u.ext2_i.i_flags = flags;
+
 		if (flags & EXT2_SYNC_FL)
 			inode->i_flags |= MS_SYNCHRONOUS;
 		else
@@ -68,6 +75,7 @@
 		inode->i_ctime = CURRENT_TIME;
 		mark_inode_dirty(inode);
 		return 0;
+	}
 	case EXT2_IOC_GETVERSION:
 		return put_user(inode->i_generation, (int *) arg);
 	case EXT2_IOC_SETVERSION:
diff -u --recursive --new-file v2.3.9/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.3.9/linux/fs/fat/dir.c	Thu May 13 23:18:20 1999
+++ linux/fs/fat/dir.c	Tue Jul  6 22:19:38 1999
@@ -295,6 +295,8 @@
 	char bufname[14];
 	char *ptname = bufname;
 	int dotoffset = 0;
+	unsigned long *furrfu = &lpos;
+	unsigned long dummy;
 
 	cpos = filp->f_pos;
 /* Fake . and .. for the root directory. */
@@ -305,8 +307,11 @@
 			cpos++;
 			filp->f_pos++;
 		}
-		if (cpos == 2)
+		if (cpos == 2) {
+			dummy = 2;
+			furrfu = &dummy;
 			cpos = 0;
+		}
 	}
 	if (cpos & (sizeof(struct msdos_dir_entry)-1))
 		return -ENOENT;
@@ -440,7 +445,7 @@
 	if (!long_slots||shortnames) {
 		if (both)
 			bufname[i] = '\0';
-		if (filldir(dirent, bufname, i, lpos, inum) < 0)
+		if (filldir(dirent, bufname, i, *furrfu, inum) < 0)
 			goto FillFailed;
 	} else {
 		char longname[275];
@@ -451,11 +456,12 @@
 			memcpy(&longname[long_len+1], bufname, i);
 			long_len += i;
 		}
-		if (filldir(dirent, longname, long_len, lpos, inum) < 0)
+		if (filldir(dirent, longname, long_len, *furrfu, inum) < 0)
 			goto FillFailed;
 	}
 
 RecEnd:
+	furrfu = &lpos;
 	filp->f_pos = cpos;
 	goto GetNew;
 EODir:
diff -u --recursive --new-file v2.3.9/linux/fs/fat/mmap.c linux/fs/fat/mmap.c
--- v2.3.9/linux/fs/fat/mmap.c	Sun Mar  7 10:40:14 1999
+++ linux/fs/fat/mmap.c	Fri Jul  2 15:15:51 1999
@@ -87,8 +87,7 @@
 	NULL,			/* advise */
 	fat_file_mmap_nopage,	/* nopage */
 	NULL,			/* wppage */
-	NULL,			/* swapout */
-	NULL,			/* swapin */
+	NULL			/* swapout */
 };
 
 /*
diff -u --recursive --new-file v2.3.9/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.3.9/linux/fs/fcntl.c	Mon Jun  7 12:10:22 1999
+++ linux/fs/fcntl.c	Sun Jul  4 10:18:52 1999
@@ -12,27 +12,19 @@
 
 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
 
-static inline int dupfd(unsigned int fd, unsigned int arg)
+static inline int dupfd(struct file *file, unsigned int arg)
 {
 	struct files_struct * files = current->files;
-	struct file * file;
 	int error;
 
-	error = -EINVAL;
-	if (arg >= NR_OPEN)
-		goto out;
-
-	error = -EBADF;
-	file = fget(fd);
-	if (!file)
-		goto out;
-
 	error = -EMFILE;
+	write_lock(&files->file_lock);
 	arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
 	if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
 		goto out_putf;
 	FD_SET(arg, &files->open_fds);
 	FD_CLR(arg, &files->close_on_exec);
+	write_unlock(&files->file_lock);
 	fd_install(arg, file);
 	error = arg;
 out:
@@ -46,31 +38,35 @@
 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
 {
 	int err = -EBADF;
+	struct file * file;
 
-	lock_kernel();
-	if (!fcheck(oldfd))
-		goto out;
+	read_lock(&current->files->file_lock);
+	if (!(file = fcheck(oldfd)))
+		goto out_unlock;
 	err = newfd;
 	if (newfd == oldfd)
-		goto out;
+		goto out_unlock;
 	err = -EBADF;
 	if (newfd >= NR_OPEN)
-		goto out;	/* following POSIX.1 6.2.1 */
+		goto out_unlock;	/* following POSIX.1 6.2.1 */
+	get_file(file);
+	read_unlock(&current->files->file_lock);
 
 	sys_close(newfd);
-	err = dupfd(oldfd, newfd);
+	err = dupfd(file, newfd);
 out:
-	unlock_kernel();
 	return err;
+out_unlock:
+	read_unlock(&current->files->file_lock);
+	goto out;
 }
 
 asmlinkage int sys_dup(unsigned int fildes)
 {
-	int ret;
-
-	lock_kernel();
-	ret = dupfd(fildes, 0);
-	unlock_kernel();
+	int ret = -EBADF;
+	struct file * file = fget(fildes);
+	if (file)
+		ret = dupfd(file, 0);
 	return ret;
 }
 
@@ -107,14 +103,18 @@
 	struct file * filp;
 	long err = -EBADF;
 
-	lock_kernel();
 	filp = fget(fd);
 	if (!filp)
 		goto out;
 	err = 0;
+	lock_kernel();
 	switch (cmd) {
 		case F_DUPFD:
-			err = dupfd(fd, arg);
+			err = -EINVAL;
+			if (arg < NR_OPEN) {
+				get_file(filp);
+				err = dupfd(filp, arg);
+			}
 			break;
 		case F_GETFD:
 			err = FD_ISSET(fd, &current->files->close_on_exec);
@@ -178,8 +178,8 @@
 			break;
 	}
 	fput(filp);
-out:
 	unlock_kernel();
+out:
 	return err;
 }
 
diff -u --recursive --new-file v2.3.9/linux/fs/fifo.c linux/fs/fifo.c
--- v2.3.9/linux/fs/fifo.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/fifo.c	Sun Jul  4 10:02:30 1999
@@ -179,6 +179,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
diff -u --recursive --new-file v2.3.9/linux/fs/file_table.c linux/fs/file_table.c
--- v2.3.9/linux/fs/file_table.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/file_table.c	Sat Jul  3 10:42:21 1999
@@ -9,6 +9,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 /* SLAB cache for filp's. */
 static kmem_cache_t *filp_cache;
@@ -18,37 +19,12 @@
 int nr_free_files = 0;	/* read only */
 int max_files = NR_FILE;/* tunable */
 
-/* Free list management, if you are here you must have f_count == 0 */
-static struct file * free_filps = NULL;
-
-static void insert_file_free(struct file *file)
-{
-	if((file->f_next = free_filps) != NULL)
-		free_filps->f_pprev = &file->f_next;
-	free_filps = file;
-	file->f_pprev = &free_filps;
-	nr_free_files++;
-}
-
-/* The list of in-use filp's must be exported (ugh...) */
-struct file *inuse_filps = NULL;
-
-static inline void put_inuse(struct file *file)
-{
-	if((file->f_next = inuse_filps) != NULL)
-		inuse_filps->f_pprev = &file->f_next;
-	inuse_filps = file;
-	file->f_pprev = &inuse_filps;
-}
-
-/* It does not matter which list it is on. */
-static inline void remove_filp(struct file *file)
-{
-	if(file->f_next)
-		file->f_next->f_pprev = file->f_pprev;
-	*file->f_pprev = file->f_next;
-}
-
+/* Here the new files go */
+static LIST_HEAD(anon_list);
+/* And here the free ones sit */
+static LIST_HEAD(free_list);
+/* public *and* exported. Not pretty! */
+spinlock_t files_lock = SPIN_LOCK_UNLOCKED;
 
 void __init file_table_init(void)
 {
@@ -67,24 +43,30 @@
 /* Find an unused file structure and return a pointer to it.
  * Returns NULL, if there are no more free file structures or
  * we run out of memory.
+ *
+ * SMP-safe.
  */
 struct file * get_empty_filp(void)
 {
 	static int old_max = 0;
 	struct file * f;
 
+	file_list_lock();
 	if (nr_free_files > NR_RESERVED_FILES) {
 	used_one:
-		f = free_filps;
-		remove_filp(f);
+		f = list_entry(free_list.next, struct file, f_list);
+		list_del(&f->f_list);
 		nr_free_files--;
 	new_one:
+		file_list_unlock();
 		memset(f, 0, sizeof(*f));
-		atomic_set(&f->f_count, 1);
+		atomic_set(&f->f_count,1);
 		f->f_version = ++event;
 		f->f_uid = current->fsuid;
 		f->f_gid = current->fsgid;
-		put_inuse(f);
+		file_list_lock();
+		list_add(&f->f_list, &anon_list);
+		file_list_unlock();
 		return f;
 	}
 	/*
@@ -96,7 +78,9 @@
 	 * Allocate a new one if we're below the limit.
 	 */
 	if (nr_files < max_files) {
+		file_list_unlock();
 		f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+		file_list_lock();
 		if (f) {
 			nr_files++;
 			goto new_one;
@@ -108,6 +92,7 @@
 		printk("VFS: file-max limit %d reached\n", max_files);
 		old_max = max_files;
 	}
+	file_list_unlock();
 	return NULL;
 }
 
@@ -131,20 +116,77 @@
 		return 0;
 }
 
-void fput(struct file *file)
+void _fput(struct file *file)
 {
-	if (atomic_dec_and_test(&file->f_count)) {
-		locks_remove_flock(file);
-		__fput(file);
-		remove_filp(file);
-		insert_file_free(file);
-	}
+	atomic_inc(&file->f_count);
+
+	lock_kernel();
+	locks_remove_flock(file);	/* Still need the */
+	__fput(file);			/* big lock here. */
+	unlock_kernel();
+
+	atomic_set(&file->f_count, 0);
+	file_list_lock();
+	list_del(&file->f_list);
+	list_add(&file->f_list, &free_list);
+	nr_free_files++;
+	file_list_unlock();
 }
 
+/* Here. put_filp() is SMP-safe now. */
+
 void put_filp(struct file *file)
 {
-	if (atomic_dec_and_test(&file->f_count)) {
-		remove_filp(file);
-		insert_file_free(file);
+	if(atomic_dec_and_test(&file->f_count)) {
+		file_list_lock();
+		list_del(&file->f_list);
+		list_add(&file->f_list, &free_list);
+		nr_free_files++;
+		file_list_unlock();
+	}
+}
+
+void file_move(struct file *file, struct list_head *list)
+{
+	if (!list)
+		return;
+	file_list_lock();
+	list_del(&file->f_list);
+	list_add(&file->f_list, list);
+	file_list_unlock();
+}
+
+void file_moveto(struct file *new, struct file *old)
+{
+	file_list_lock();
+	list_del(&new->f_list);
+	list_add(&new->f_list, &old->f_list);
+	file_list_unlock();
+}
+
+int fs_may_remount_ro(struct super_block *sb)
+{
+	struct list_head *p;
+
+	/* Check that no files are currently opened for writing. */
+	file_list_lock();
+	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+		struct file *file = list_entry(p, struct file, f_list);
+		struct inode *inode = file->f_dentry->d_inode;
+		if (!inode)
+			continue;
+
+		/* File with pending delete? */
+		if (inode->i_nlink == 0)
+			goto too_bad;
+
+		/* Writable file? */
+		if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
+			return 0;
 	}
+	file_list_unlock();
+	return 1; /* Tis' cool bro. */
+too_bad:
+	file_list_unlock();
+	return 0;
 }
diff -u --recursive --new-file v2.3.9/linux/fs/inode.c linux/fs/inode.c
--- v2.3.9/linux/fs/inode.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/inode.c	Mon Jul  5 20:34:31 1999
@@ -130,6 +130,7 @@
 	INIT_LIST_HEAD(&inode->i_hash);
 	INIT_LIST_HEAD(&inode->i_dentry);
 	sema_init(&inode->i_sem, 1);
+	spin_lock_init(&inode->i_shared_lock);
 }
 
 static inline void write_inode(struct inode *inode)
@@ -523,7 +524,7 @@
 	inode->i_sock = 0;
 	inode->i_op = NULL;
 	inode->i_nlink = 1;
-	inode->i_writecount = 0;
+	atomic_set(&inode->i_writecount, 0);
 	inode->i_size = 0;
 	inode->i_generation = 0;
 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
@@ -816,31 +817,6 @@
 	if (max > MAX_INODE)
 		max = MAX_INODE;
 	max_inodes = max;
-}
-
-/* This belongs in file_table.c, not here... */
-int fs_may_remount_ro(struct super_block *sb)
-{
-	struct file *file;
-
-	/* Check that no files are currently opened for writing. */
-	for (file = inuse_filps; file; file = file->f_next) {
-		struct inode *inode;
-		if (!file->f_dentry)
-			continue;
-		inode = file->f_dentry->d_inode;
-		if (!inode || inode->i_sb != sb)
-			continue;
-
-		/* File with pending delete? */
-		if (inode->i_nlink == 0)
-			return 0;
-
-		/* Writable file? */
-		if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
-			return 0;
-	}
-	return 1; /* Tis' cool bro. */
 }
 
 void update_atime (struct inode *inode)
diff -u --recursive --new-file v2.3.9/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.3.9/linux/fs/ioctl.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/ioctl.c	Mon Jul  5 20:33:16 1999
@@ -25,6 +25,8 @@
 				return -EBADF;
 		    	if (inode->i_op->get_block == NULL)
 				return -EINVAL;
+			if (!capable(CAP_SYS_RAWIO))
+				return -EPERM;
 			if ((error = get_user(block, (int *) arg)) != 0)
 				return error;
 
@@ -52,11 +54,11 @@
 	unsigned int flag;
 	int on, error = -EBADF;
 
-	lock_kernel();
 	filp = fget(fd);
 	if (!filp)
 		goto out;
 	error = 0;
+	lock_kernel();
 	switch (cmd) {
 		case FIOCLEX:
 			FD_SET(fd, &current->files->close_on_exec);
@@ -107,8 +109,8 @@
 				error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
 	}
 	fput(filp);
+	unlock_kernel();
 
 out:
-	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.3.9/linux/fs/locks.c linux/fs/locks.c
--- v2.3.9/linux/fs/locks.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/locks.c	Mon Jul  5 20:11:07 1999
@@ -341,7 +341,11 @@
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
 		if (error < 0)
 			goto out_putf;
-		fl = &file_lock;
+		else if (error == LOCK_USE_CLNT)
+		  /* Bypass for NFS with no locking - 2.0.36 compat */
+		  fl = posix_test_lock(filp, &file_lock);
+		else
+		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
 	} else {
 		fl = posix_test_lock(filp, &file_lock);
 	}
@@ -402,14 +406,17 @@
 	 * and shared.
 	 */
 	if (IS_MANDLOCK(inode) &&
-	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
-	    inode->i_mmap) {
-		struct vm_area_struct *vma = inode->i_mmap;
-		error = -EAGAIN;
-		do {
-			if (vma->vm_flags & VM_MAYSHARE)
-				goto out_putf;
-		} while ((vma = vma->vm_next_share) != NULL);
+	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+		struct vm_area_struct *vma;
+		spin_lock(&inode->i_shared_lock);
+		for(vma = inode->i_mmap;vma;vma = vma->vm_next_share) {
+			if (!(vma->vm_flags & VM_MAYSHARE))
+				continue;
+			spin_unlock(&inode->i_shared_lock);
+			error = -EAGAIN;
+			goto out_putf;
+		}
+		spin_unlock(&inode->i_shared_lock);
 	}
 
 	error = -EINVAL;
@@ -546,47 +553,23 @@
 	return (cfl);
 }
 
-int locks_verify_locked(struct inode *inode)
-{
-	/* Candidates for mandatory locking have the setgid bit set
-	 * but no group execute bit -  an otherwise meaningless combination.
-	 */
-	if (IS_MANDLOCK(inode) &&
-	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-		return (locks_mandatory_locked(inode));
-	return (0);
-}
-
-int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
-		      loff_t offset, size_t count)
-{
-	/* Candidates for mandatory locking have the setgid bit set
-	 * but no group execute bit -  an otherwise meaningless combination.
-	 */
-	if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
-		int retval;
-		lock_kernel();
-		retval = locks_mandatory_area(read_write, inode, filp, offset, count);
-		unlock_kernel();
-		return retval;
-	}
-	return 0;
-}
-
 int locks_mandatory_locked(struct inode *inode)
 {
 	fl_owner_t owner = current->files;
 	struct file_lock *fl;
 
-	/* Search the lock list for this inode for any POSIX locks.
+	/*
+	 * Search the lock list for this inode for any POSIX locks.
 	 */
+	lock_kernel();
 	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
 		if (!(fl->fl_flags & FL_POSIX))
 			continue;
 		if (fl->fl_owner != owner)
-			return (-EAGAIN);
+			break;
 	}
-	return (0);
+	unlock_kernel();
+	return fl ? -EAGAIN : 0;
 }
 
 int locks_mandatory_area(int read_write, struct inode *inode,
@@ -595,6 +578,7 @@
 {
 	struct file_lock *fl;
 	struct file_lock tfl;
+	int error;
 
 	memset(&tfl, 0, sizeof(tfl));
 
@@ -607,31 +591,39 @@
 	tfl.fl_start = offset;
 	tfl.fl_end = offset + count - 1;
 
+	error = 0;
+	lock_kernel();
+
 repeat:
 	/* Search the lock list for this inode for locks that conflict with
 	 * the proposed read/write.
 	 */
-	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+	for (fl = inode->i_flock; ; fl = fl->fl_next) {
+		error = 0;
+		if (!fl)
+			break;
 		if (!(fl->fl_flags & FL_POSIX))
 			continue;
 		/* Block for writes against a "read" lock,
 		 * and both reads and writes against a "write" lock.
 		 */
 		if (posix_locks_conflict(fl, &tfl)) {
+			error = -EAGAIN;
 			if (filp && (filp->f_flags & O_NONBLOCK))
-				return (-EAGAIN);
+				break;
+			error = -ERESTARTSYS;
 			if (signal_pending(current))
-				return (-ERESTARTSYS);
+				break;
+			error = -EDEADLK;
 			if (posix_locks_deadlock(&tfl, fl))
-				return (-EDEADLK);
+				break;
 
 			locks_insert_block(fl, &tfl);
 			interruptible_sleep_on(&tfl.fl_wait);
 			locks_delete_block(fl, &tfl);
 
-			if (signal_pending(current))
-				return (-ERESTARTSYS);
-			/* If we've been sleeping someone might have
+			/*
+			 * If we've been sleeping someone might have
 			 * changed the permissions behind our back.
 			 */
 			if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID)
@@ -639,7 +631,8 @@
 			goto repeat;
 		}
 	}
-	return (0);
+	unlock_kernel();
+	return error;
 }
 
 /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
diff -u --recursive --new-file v2.3.9/linux/fs/minix/file.c linux/fs/minix/file.c
--- v2.3.9/linux/fs/minix/file.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/minix/file.c	Tue Jul  6 19:08:33 1999
@@ -7,7 +7,6 @@
  */
 
 #include <linux/sched.h>
-#include <linux/minix_fs.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/fcntl.h>
@@ -25,7 +24,6 @@
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
 #include <linux/fs.h>
-#include <linux/minix_fs.h>
 
 /*
  * Write to a file (through the page cache).
diff -u --recursive --new-file v2.3.9/linux/fs/namei.c linux/fs/namei.c
--- v2.3.9/linux/fs/namei.c	Sat May 15 23:43:05 1999
+++ linux/fs/namei.c	Mon Jul  5 20:34:31 1999
@@ -171,18 +171,22 @@
  * 0: no writers, no VM_DENYWRITE mappings
  * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
  * > 0: (i_writecount) users are writing to the file.
+ *
+ * WARNING: as soon as we will move get_write_access(), do_mmap() or
+ * prepare_binfmt() out of the big lock we will need a spinlock protecting
+ * the checks in all 3. For the time being it is not needed.
  */
 int get_write_access(struct inode * inode)
 {
-	if (inode->i_writecount < 0)
+	if (atomic_read(&inode->i_writecount) < 0)
 		return -ETXTBSY;
-	inode->i_writecount++;
+	atomic_inc(&inode->i_writecount);
 	return 0;
 }
 
 void put_write_access(struct inode * inode)
 {
-	inode->i_writecount--;
+	atomic_dec(&inode->i_writecount);
 }
 
 /*
diff -u --recursive --new-file v2.3.9/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.9/linux/fs/ncpfs/dir.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/ncpfs/dir.c	Mon Jul  5 20:35:18 1999
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
-#include <linux/errno.h>
 #include <linux/locks.h>
 
 #include <linux/ncp_fs.h>
diff -u --recursive --new-file v2.3.9/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.3.9/linux/fs/ncpfs/mmap.c	Fri May 14 12:43:00 1999
+++ linux/fs/ncpfs/mmap.c	Fri Jul  2 15:15:51 1999
@@ -98,8 +98,7 @@
 	NULL,			/* advise */
 	ncp_file_mmap_nopage,	/* nopage */
 	NULL,			/* wppage */
-	NULL,			/* swapout */
-	NULL,			/* swapin */
+	NULL			/* swapout */
 };
 
 
diff -u --recursive --new-file v2.3.9/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.3.9/linux/fs/nfs/read.c	Sat Jun 19 11:38:49 1999
+++ linux/fs/nfs/read.c	Tue Jul  6 10:06:18 1999
@@ -90,8 +90,9 @@
 
 		/* Set up arguments and perform rpc call */
 		nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize);
-		result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ,
-					&rqst.ra_args, &rqst.ra_res, flags);
+		lock_kernel();
+		result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rqst.ra_args, &rqst.ra_res, flags);
+		unlock_kernel();
 
 		/*
 		 * Even if we had a partial success we can't mark the page
diff -u --recursive --new-file v2.3.9/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.3.9/linux/fs/nfs/write.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/nfs/write.c	Sat Jul  3 10:44:05 1999
@@ -305,6 +305,7 @@
 		goto out_req;
 
 	/* Put the task on inode's writeback request list. */
+	get_file(file);
 	wreq->wb_file = file;
 	wreq->wb_pid    = current->pid;
 	wreq->wb_page   = page;
@@ -467,7 +468,6 @@
 	 * The IO completion will then free the page and the dentry.
 	 */
 	get_page(page);
-	atomic_inc(&file->f_count);
 
 	/* Schedule request */
 	synchronous = schedule_write_request(req, synchronous);
diff -u --recursive --new-file v2.3.9/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- v2.3.9/linux/fs/nfsd/nfsctl.c	Sat Jan  2 17:55:06 1999
+++ linux/fs/nfsd/nfsctl.c	Mon Jul  5 20:35:18 1999
@@ -18,7 +18,6 @@
 #include <linux/fcntl.h>
 #include <linux/net.h>
 #include <linux/in.h>
-#include <linux/version.h>
 #include <linux/unistd.h>
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
diff -u --recursive --new-file v2.3.9/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.9/linux/fs/nfsd/vfs.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/nfsd/vfs.c	Mon Jul  5 20:34:31 1999
@@ -585,7 +585,7 @@
 		 * nice and simple solution (IMHO), and it seems to
 		 * work:-)
 		 */
-		if (EX_WGATHER(exp) && (inode->i_writecount > 1
+		if (EX_WGATHER(exp) && (atomic_read(&inode->i_writecount) > 1
 		 || (last_ino == inode->i_ino && last_dev == inode->i_dev))) {
 #if 0
 			interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
diff -u --recursive --new-file v2.3.9/linux/fs/open.c linux/fs/open.c
--- v2.3.9/linux/fs/open.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/open.c	Mon Jul  5 20:49:52 1999
@@ -37,29 +37,21 @@
 asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
 {
 	struct file * file;
-	struct inode * inode;
-	struct dentry * dentry;
 	struct super_block * sb;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
-	error = -ENOENT;
-	if (!(dentry = file->f_dentry))
-		goto out_putf;
-	if (!(inode = dentry->d_inode))
-		goto out_putf;
 	error = -ENODEV;
-	sb = inode->i_sb;
+	sb = file->f_dentry->d_inode->i_sb;
+	lock_kernel();
 	if (sb && sb->s_op && sb->s_op->statfs)
 		error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
-out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -143,7 +135,6 @@
 	struct file * file;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -162,12 +153,13 @@
 	error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
 				  length<inode->i_size ? length : inode->i_size,
 				  abs(inode->i_size - length));
+	lock_kernel();
 	if (!error)
 		error = do_truncate(dentry, length);
+	unlock_kernel();
 out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -361,8 +353,6 @@
 	struct inode *inode;
 	int error;
 
-	lock_kernel();
-
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -378,16 +368,17 @@
 	if (!S_ISDIR(inode->i_mode))
 		goto out_putf;
 
+	lock_kernel();
 	error = permission(inode, MAY_EXEC);
 	if (!error) {
 		struct dentry *tmp = current->fs->pwd;
 		current->fs->pwd = dget(dentry);
 		dput(tmp);
 	}
+	unlock_kernel();
 out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -439,7 +430,6 @@
 	int err = -EBADF;
 	struct iattr newattrs;
 
-	lock_kernel();
 	file = fget(fd);
 	if (!file)
 		goto out;
@@ -460,12 +450,13 @@
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+	lock_kernel();
 	err = notify_change(dentry, &newattrs);
+	unlock_kernel();
 
 out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return err;
 }
 
@@ -601,17 +592,17 @@
 	struct file * file;
 	int error = -EBADF;
 
-	lock_kernel();
 	file = fget(fd);
 	if (!file)
 		goto out;
 	error = -ENOENT;
+	lock_kernel();
 	if ((dentry = file->f_dentry) != NULL)
 		error = chown_common(dentry, user, group);
+	unlock_kernel();
 	fput(file);
 
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -663,6 +654,8 @@
 	f->f_op = NULL;
 	if (inode->i_op)
 		f->f_op = inode->i_op->default_file_ops;
+	if (inode->i_sb)
+		file_move(f, &inode->i_sb->s_files);
 	if (f->f_op && f->f_op->open) {
 		error = f->f_op->open(inode,f);
 		if (error)
@@ -693,6 +686,8 @@
 	int fd, error;
 
 	error = -EMFILE;
+
+	write_lock(&files->file_lock);
 	fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
 	/*
 	 * N.B. For clone tasks sharing a files structure, this test
@@ -715,12 +710,15 @@
 	error = fd;
 
 out:
+	write_unlock(&files->file_lock);
 	return error;
 }
 
 inline void put_unused_fd(unsigned int fd)
 {
+	write_lock(&current->files->file_lock);
 	FD_CLR(fd, &current->files->open_fds);
+	write_unlock(&current->files->file_lock);
 }
 
 asmlinkage int sys_open(const char * filename, int flags, int mode)
@@ -731,17 +729,18 @@
 	tmp = getname(filename);
 	fd = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
-		lock_kernel();
 		fd = get_unused_fd();
 		if (fd >= 0) {
-			struct file * f = filp_open(tmp, flags, mode);
+			struct file * f;
+			lock_kernel();
+			f = filp_open(tmp, flags, mode);
+			unlock_kernel();
 			error = PTR_ERR(f);
 			if (IS_ERR(f))
 				goto out_error;
 			fd_install(fd, f);
 		}
 out:
-		unlock_kernel();
 		putname(tmp);
 	}
 	return fd;
@@ -790,7 +789,7 @@
 	int retval;
 	struct dentry *dentry = filp->f_dentry;
 
-	if (!atomic_read(&filp->f_count)) {
+	if (!file_count(filp)) {
 		printk("VFS: Close: file count is 0\n");
 		return 0;
 	}
@@ -812,19 +811,24 @@
 {
 	int error;
 	struct file * filp;
+	struct files_struct * files = current->files;
 
-	lock_kernel();
 	error = -EBADF;
-	filp = fcheck(fd);
-	if (filp) {
-		struct files_struct * files = current->files;
-		files->fd[fd] = NULL;
-		put_unused_fd(fd);
-		FD_CLR(fd, &files->close_on_exec);
-		error = filp_close(filp, files);
-	}
+	write_lock(&files->file_lock);
+	filp = frip(fd);
+	if (!filp)
+		goto out_unlock;
+	FD_CLR(fd, &files->close_on_exec);
+	write_unlock(&files->file_lock);
+	put_unused_fd(fd);
+	lock_kernel();
+	error = filp_close(filp, files);
 	unlock_kernel();
+out:
 	return error;
+out_unlock:
+	write_unlock(&files->file_lock);
+	goto out;
 }
 
 /*
@@ -835,14 +839,14 @@
 {
 	int ret = -EPERM;
 
-	lock_kernel();
 	if (!capable(CAP_SYS_TTY_CONFIG))
 		goto out;
 	/* If there is a controlling tty, hang it up */
+	lock_kernel();
 	if (current->tty)
 		tty_vhangup(current->tty);
+	unlock_kernel();
 	ret = 0;
 out:
-	unlock_kernel();
 	return ret;
 }
diff -u --recursive --new-file v2.3.9/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.9/linux/fs/pipe.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/pipe.c	Tue Jul  6 19:08:33 1999
@@ -27,7 +27,7 @@
 /* Florian Coosmann (FGC)                                ^ current = 1       */
 /* Additionally, we now use locking technique. This prevents race condition  */
 /* in case of paging and multiple read/write on the same pipe. (FGC)         */
-
+/* Reads with count = 0 should always return 0. Julian Bradfield 1999-06-07. */
 
 static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count)
 {
@@ -144,9 +144,12 @@
 {
 	ssize_t retval;
 
+
 	if (ppos != &filp->f_pos)
 		return -ESPIPE;
 
+	if ( !count ) return 0;
+
 	lock_kernel();
 	retval = do_pipe_read(filp, buf, count);
 	unlock_kernel();
@@ -480,6 +483,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
diff -u --recursive --new-file v2.3.9/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.3.9/linux/fs/proc/fd.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/proc/fd.c	Sun Jul  4 10:18:52 1999
@@ -104,7 +104,7 @@
 	read_lock(&tasklist_lock);
 	file = NULL;
 	p = find_task_by_pid(pid);
-	if (p)
+	if (p && p->files)
 		file = fcheck_task(p, fd);
 	read_unlock(&tasklist_lock);
 
@@ -114,7 +114,7 @@
 	 *	is NULL
 	 */
 
-	if (!file || !file->f_dentry)
+	if (!file)
 		goto out;
 
 	ino = (pid << 16) + PROC_PID_FD_DIR + fd;
@@ -161,10 +161,9 @@
 
 	for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
 	{
-		struct file * file = fcheck_task(p, fd);
 		unsigned int i,j;
 
-		if (!file || !file->f_dentry)
+		if (!fcheck_task(p, fd))
 			continue;
 
 		j = NUMBUF;
diff -u --recursive --new-file v2.3.9/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.3.9/linux/fs/proc/inode.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/proc/inode.c	Sun Jul  4 10:18:52 1999
@@ -87,13 +87,26 @@
 	}
 }
 
+struct super_block *proc_super_blocks = NULL;
+
+static void proc_put_super(struct super_block *sb)
+{
+	struct super_block **p = &proc_super_blocks;
+	while (*p != sb) {
+		if (!*p)	/* should never happen */
+			return;
+		p = (struct super_block **)&(*p)->u.generic_sbp;
+	}
+	*p = (struct super_block *)(*p)->u.generic_sbp;
+}
+
 static struct super_operations proc_sops = { 
 	proc_read_inode,
 	proc_write_inode,
 	proc_put_inode,
 	proc_delete_inode,	/* delete_inode(struct inode *) */
 	NULL,
-	NULL,
+	proc_put_super,
 	NULL,
 	proc_statfs,
 	NULL
@@ -323,6 +336,8 @@
 	if (!s->s_root)
 		goto out_no_root;
 	parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
+	s->u.generic_sbp = (void*) proc_super_blocks;
+	proc_super_blocks = s;
 	unlock_super(s);
 	return s;
 
@@ -385,9 +400,12 @@
 	if (ino & PROC_PID_FD_DIR) {
 		struct file * file;
 		ino &= 0x7fff;
+		if (!p->files)	/* can we ever get here if that's the case? */
+			goto out_unlock;
+		read_lock(&p->files->file_lock);
 		file = fcheck_task(p, ino);
 		if (!file)
-			goto out_unlock;
+			goto out_unlock2;
 
 		inode->i_op = &proc_link_inode_operations;
 		inode->i_size = 64;
@@ -396,6 +414,8 @@
 			inode->i_mode |= S_IRUSR | S_IXUSR;
 		if (file->f_mode & 2)
 			inode->i_mode |= S_IWUSR | S_IXUSR;
+out_unlock2:
+		read_unlock(&p->files->file_lock);
 	}
 out_unlock:
 	/* Defer unlocking until we're done with the task */
diff -u --recursive --new-file v2.3.9/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.3.9/linux/fs/proc/link.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/proc/link.c	Mon Jul  5 19:59:55 1999
@@ -119,10 +119,14 @@
 			if (ino & PROC_PID_FD_DIR) {
 				struct file * file;
 				ino &= 0x7fff;
+				if (!p->files) /* shouldn't happen here */
+					goto out_unlock;
+				read_lock(&p->files->file_lock);
 				file = fcheck_task(p, ino);
 				if (!file || !file->f_dentry)
 					goto out_unlock;
 				result = file->f_dentry;
+				read_unlock(&p->files->file_lock);
 				goto out_dget;
 			}
 	}
@@ -146,6 +150,9 @@
 	char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
 	int len;
 
+	if(tmp==NULL)
+		return -ENOMEM;
+		
 	/* Check for special dentries.. */
 	pattern = NULL;
 	inode = dentry->d_inode;
diff -u --recursive --new-file v2.3.9/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.9/linux/fs/proc/root.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/proc/root.c	Sat Jul  3 10:42:21 1999
@@ -365,24 +365,36 @@
  */
 static void proc_kill_inodes(int ino)
 {
-	struct file *filp;
+	struct list_head *p;
+	struct super_block *sb;
 
-	/* inuse_filps is protected by the single kernel lock */
-	for (filp = inuse_filps; filp; filp = filp->f_next) {
-		struct dentry * dentry;
-		struct inode * inode;
+	/*
+	 * Actually it's a partial revoke(). We have to go through all
+	 * copies of procfs. proc_super_blocks is protected by the big
+	 * lock for the time being.
+	 */
+	for (sb = proc_super_blocks;
+	     sb;
+	     sb = (struct super_block*)sb->u.generic_sbp) {
+		file_list_lock();
+		for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+			struct file * filp = list_entry(p, struct file, f_list);
+			struct dentry * dentry;
+			struct inode * inode;
 
-		dentry = filp->f_dentry;
-		if (!dentry)
-			continue;
-		if (dentry->d_op != &proc_dentry_operations)
-			continue;
-		inode = dentry->d_inode;
-		if (!inode)
-			continue;
-		if (inode->i_ino != ino)
-			continue;
-		filp->f_op = NULL;
+			dentry = filp->f_dentry;
+			if (!dentry)
+				continue;
+			if (dentry->d_op != &proc_dentry_operations)
+				continue;
+			inode = dentry->d_inode;
+			if (!inode)
+				continue;
+			if (inode->i_ino != ino)
+				continue;
+			filp->f_op = NULL;
+		}
+		file_list_unlock();
 	}
 }
 
diff -u --recursive --new-file v2.3.9/linux/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- v2.3.9/linux/fs/qnx4/dir.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/qnx4/dir.c	Mon Jul  5 19:59:55 1999
@@ -41,6 +41,11 @@
 
 	while (filp->f_pos < inode->i_size) {
 		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
+		if(bh==NULL)
+		{
+			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
+			break;
+		}
 		i = (filp->f_pos - (((filp->f_pos >> 6) >> 3) << 9)) & 0x3f;
 		while (i < QNX4_INODES_PER_BLOCK) {
 			offset = i * QNX4_DIR_ENTRY_SIZE;
diff -u --recursive --new-file v2.3.9/linux/fs/qnx4/symlinks.c linux/fs/qnx4/symlinks.c
--- v2.3.9/linux/fs/qnx4/symlinks.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/qnx4/symlinks.c	Mon Jul  5 19:59:55 1999
@@ -98,12 +98,12 @@
 	}
 	bh = bread(inode->i_dev, qnx4_ino->i_first_xtnt.xtnt_blk,
 		   QNX4_BLOCK_SIZE);
-	QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
-		   bh->b_data));
 	if (bh == NULL) {
 		QNX4DEBUG(("qnx4: NULL symlink bh\n"));
 		return 0;
 	}
+	QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
+		   bh->b_data));
 	if (bh->b_data[0] != 0) {
 		i = 0;
 		while (i < buflen && (c = bh->b_data[i])) {
diff -u --recursive --new-file v2.3.9/linux/fs/select.c linux/fs/select.c
--- v2.3.9/linux/fs/select.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/select.c	Sun Jul  4 10:19:34 1999
@@ -64,9 +64,9 @@
 		if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
 			struct poll_table_entry * entry;
 ok_table:
-			entry = p->entry + p->nr;
-			entry->filp = filp;
-			atomic_inc(&filp->f_count);
+		 	entry = p->entry + p->nr;
+		 	get_file(filp);
+		 	entry->filp = filp;
 			entry->wait_address = wait_address;
 			init_waitqueue_entry(&entry->wait, current);
 			add_wait_queue(wait_address,&entry->wait);
@@ -164,9 +164,11 @@
 		wait = wait_table;
 	}
 
-	lock_kernel();
-
+	read_lock(&current->files->file_lock);
 	retval = max_select_fd(n, fds);
+	read_unlock(&current->files->file_lock);
+
+	lock_kernel();
 	if (retval < 0)
 		goto out;
 	n = retval;
diff -u --recursive --new-file v2.3.9/linux/fs/super.c linux/fs/super.c
--- v2.3.9/linux/fs/super.c	Thu Jun 17 23:18:29 1999
+++ linux/fs/super.c	Sat Jul  3 10:42:21 1999
@@ -531,6 +531,7 @@
 		INIT_LIST_HEAD(&s->s_dirty);
 		list_add (&s->s_list, super_blocks.prev);
 		init_waitqueue_head(&s->s_wait);
+		INIT_LIST_HEAD(&s->s_files);
 	}
 	return s;
 }
diff -u --recursive --new-file v2.3.9/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v2.3.9/linux/fs/sysv/file.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/sysv/file.c	Mon Jul  5 20:35:18 1999
@@ -30,9 +30,6 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
-
 /*
  * Write to a file (through the page cache).
  */
diff -u --recursive --new-file v2.3.9/linux/fs/ufs/balloc.c linux/fs/ufs/balloc.c
--- v2.3.9/linux/fs/ufs/balloc.c	Sun Jan 17 18:32:26 1999
+++ linux/fs/ufs/balloc.c	Mon Jul  5 19:59:55 1999
@@ -360,14 +360,22 @@
 	if (result) {
 		for (i = 0; i < oldcount; i++) {
 			bh = bread (sb->s_dev, tmp + i, sb->s_blocksize);
-			mark_buffer_clean (bh);
-			bh->b_blocknr = result + i;
-			mark_buffer_dirty (bh, 0);
-			if (IS_SYNC(inode)) {
-				ll_rw_block (WRITE, 1, &bh);
-				wait_on_buffer (bh);
+			if(bh)
+			{
+				mark_buffer_clean (bh);
+				bh->b_blocknr = result + i;
+				mark_buffer_dirty (bh, 0);
+				if (IS_SYNC(inode)) {
+					ll_rw_block (WRITE, 1, &bh);
+					wait_on_buffer (bh);
+				}
+				brelse (bh);
+			}
+			else
+			{
+				printk(KERN_ERR "ufs_new_fragments: bread fail\n");
+				return 0;
 			}
-			brelse (bh);
 		}
 		*p = SWAB32(result);
 		*err = 0;
diff -u --recursive --new-file v2.3.9/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.3.9/linux/fs/ufs/super.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/ufs/super.c	Thu Jul  1 10:45:57 1999
@@ -467,7 +467,8 @@
 	}
 	if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
 		printk("You didn't specify the type of your ufs filesystem\n\n"
-		"       mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
+		"mount -t ufs -o ufstype="
+		"sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
 		">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
 		"default is ufstype=old\n");
 		ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
diff -u --recursive --new-file v2.3.9/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.3.9/linux/fs/umsdos/file.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/umsdos/file.c	Mon Jul  5 20:35:18 1999
@@ -13,7 +13,6 @@
 #include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
-#include <linux/msdos_fs.h>
 #include <linux/umsdos_fs.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.9/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.3.9/linux/include/asm-i386/bugs.h	Tue Jun 22 14:41:36 1999
+++ linux/include/asm-i386/bugs.h	Wed Jul  7 09:51:37 1999
@@ -356,22 +356,6 @@
 
 __initfunc(static void check_cyrix_coma(void))
 {
-	if (boot_cpu_data.coma_bug) {
-		unsigned char ccr3, tmp;
-		cli();
-		ccr3 = getCx86(CX86_CCR3);
-		setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
-		tmp = getCx86(0x31);
-		setCx86(0x31, tmp | 0xf8);
-		tmp = getCx86(0x32);
-		setCx86(0x32, tmp | 0x7f);
-		setCx86(0x33, 0);
-		tmp = getCx86(0x3c);
-		setCx86(0x3c, tmp | 0x87);
-		setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-		sti();
-		printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
-	}
 }
  
 /*
diff -u --recursive --new-file v2.3.9/linux/include/asm-i386/setup.h linux/include/asm-i386/setup.h
--- v2.3.9/linux/include/asm-i386/setup.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/setup.h	Mon Jul  5 19:59:55 1999
@@ -0,0 +1,4 @@
+/*
+ *	Just a place holder. We don't want to have to test x86 before
+ *	we include stuff
+ */
diff -u --recursive --new-file v2.3.9/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.3.9/linux/include/asm-mips/processor.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-mips/processor.h	Mon Jul  5 19:44:57 1999
@@ -201,9 +201,6 @@
 	return ((unsigned long*)t->reg29)[17];
 }
 
-struct pt_regs;
-extern int (*user_mode)(struct pt_regs *);
-
 /*
  * Do necessary setup to start up a newly executed thread.
  */
diff -u --recursive --new-file v2.3.9/linux/include/asm-mips/ptrace.h linux/include/asm-mips/ptrace.h
--- v2.3.9/linux/include/asm-mips/ptrace.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-mips/ptrace.h	Mon Jul  5 19:44:57 1999
@@ -59,7 +59,7 @@
 /*
  * Does the process account for user or for system time?
  */
-#define user_mode(regs) ((regs)->cp0_status & 0x10)
+extern int (*user_mode)(struct pt_regs *);
 
 #define instruction_pointer(regs) ((regs)->cp0_epc)
 
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.3.9/linux/include/asm-sparc/asm_offsets.h	Wed May 12 08:41:15 1999
+++ linux/include/asm-sparc/asm_offsets.h	Sun Jul  4 09:53:12 1999
@@ -196,45 +196,47 @@
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x00000018
 #define ASIZ_mm_mmap_sem	0x00000020
-#define AOFF_mm_context	0x00000038
+#define AOFF_mm_page_table_lock	0x00000038
+#define ASIZ_mm_page_table_lock	0x00000001
+#define AOFF_mm_context	0x0000003c
 #define ASIZ_mm_context	0x00000004
-#define AOFF_mm_start_code	0x0000003c
+#define AOFF_mm_start_code	0x00000040
 #define ASIZ_mm_start_code	0x00000004
-#define AOFF_mm_end_code	0x00000040
+#define AOFF_mm_end_code	0x00000044
 #define ASIZ_mm_end_code	0x00000004
-#define AOFF_mm_start_data	0x00000044
+#define AOFF_mm_start_data	0x00000048
 #define ASIZ_mm_start_data	0x00000004
-#define AOFF_mm_end_data	0x00000048
+#define AOFF_mm_end_data	0x0000004c
 #define ASIZ_mm_end_data	0x00000004
-#define AOFF_mm_start_brk	0x0000004c
+#define AOFF_mm_start_brk	0x00000050
 #define ASIZ_mm_start_brk	0x00000004
-#define AOFF_mm_brk	0x00000050
+#define AOFF_mm_brk	0x00000054
 #define ASIZ_mm_brk	0x00000004
-#define AOFF_mm_start_stack	0x00000054
+#define AOFF_mm_start_stack	0x00000058
 #define ASIZ_mm_start_stack	0x00000004
-#define AOFF_mm_arg_start	0x00000058
+#define AOFF_mm_arg_start	0x0000005c
 #define ASIZ_mm_arg_start	0x00000004
-#define AOFF_mm_arg_end	0x0000005c
+#define AOFF_mm_arg_end	0x00000060
 #define ASIZ_mm_arg_end	0x00000004
-#define AOFF_mm_env_start	0x00000060
+#define AOFF_mm_env_start	0x00000064
 #define ASIZ_mm_env_start	0x00000004
-#define AOFF_mm_env_end	0x00000064
+#define AOFF_mm_env_end	0x00000068
 #define ASIZ_mm_env_end	0x00000004
-#define AOFF_mm_rss	0x00000068
+#define AOFF_mm_rss	0x0000006c
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x0000006c
+#define AOFF_mm_total_vm	0x00000070
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000070
+#define AOFF_mm_locked_vm	0x00000074
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x00000074
+#define AOFF_mm_def_flags	0x00000078
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x00000078
+#define AOFF_mm_cpu_vm_mask	0x0000007c
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x0000007c
+#define AOFF_mm_swap_cnt	0x00000080
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000080
+#define AOFF_mm_swap_address	0x00000084
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x00000084
+#define AOFF_mm_segments	0x00000088
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
@@ -471,45 +473,47 @@
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x00000018
 #define ASIZ_mm_mmap_sem	0x00000024
-#define AOFF_mm_context	0x0000003c
+#define AOFF_mm_page_table_lock	0x0000003c
+#define ASIZ_mm_page_table_lock	0x00000008
+#define AOFF_mm_context	0x00000044
 #define ASIZ_mm_context	0x00000004
-#define AOFF_mm_start_code	0x00000040
+#define AOFF_mm_start_code	0x00000048
 #define ASIZ_mm_start_code	0x00000004
-#define AOFF_mm_end_code	0x00000044
+#define AOFF_mm_end_code	0x0000004c
 #define ASIZ_mm_end_code	0x00000004
-#define AOFF_mm_start_data	0x00000048
+#define AOFF_mm_start_data	0x00000050
 #define ASIZ_mm_start_data	0x00000004
-#define AOFF_mm_end_data	0x0000004c
+#define AOFF_mm_end_data	0x00000054
 #define ASIZ_mm_end_data	0x00000004
-#define AOFF_mm_start_brk	0x00000050
+#define AOFF_mm_start_brk	0x00000058
 #define ASIZ_mm_start_brk	0x00000004
-#define AOFF_mm_brk	0x00000054
+#define AOFF_mm_brk	0x0000005c
 #define ASIZ_mm_brk	0x00000004
-#define AOFF_mm_start_stack	0x00000058
+#define AOFF_mm_start_stack	0x00000060
 #define ASIZ_mm_start_stack	0x00000004
-#define AOFF_mm_arg_start	0x0000005c
+#define AOFF_mm_arg_start	0x00000064
 #define ASIZ_mm_arg_start	0x00000004
-#define AOFF_mm_arg_end	0x00000060
+#define AOFF_mm_arg_end	0x00000068
 #define ASIZ_mm_arg_end	0x00000004
-#define AOFF_mm_env_start	0x00000064
+#define AOFF_mm_env_start	0x0000006c
 #define ASIZ_mm_env_start	0x00000004
-#define AOFF_mm_env_end	0x00000068
+#define AOFF_mm_env_end	0x00000070
 #define ASIZ_mm_env_end	0x00000004
-#define AOFF_mm_rss	0x0000006c
+#define AOFF_mm_rss	0x00000074
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x00000070
+#define AOFF_mm_total_vm	0x00000078
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000074
+#define AOFF_mm_locked_vm	0x0000007c
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x00000078
+#define AOFF_mm_def_flags	0x00000080
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_cpu_vm_mask	0x0000007c
+#define AOFF_mm_cpu_vm_mask	0x00000084
 #define ASIZ_mm_cpu_vm_mask	0x00000004
-#define AOFF_mm_swap_cnt	0x00000080
+#define AOFF_mm_swap_cnt	0x00000088
 #define ASIZ_mm_swap_cnt	0x00000004
-#define AOFF_mm_swap_address	0x00000084
+#define AOFF_mm_swap_address	0x0000008c
 #define ASIZ_mm_swap_address	0x00000004
-#define AOFF_mm_segments	0x00000088
+#define AOFF_mm_segments	0x00000090
 #define ASIZ_mm_segments	0x00000004
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc/audioio.h linux/include/asm-sparc/audioio.h
--- v2.3.9/linux/include/asm-sparc/audioio.h	Wed May 12 08:41:15 1999
+++ linux/include/asm-sparc/audioio.h	Mon Jul  5 20:35:18 1999
@@ -237,7 +237,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.3.9/linux/include/asm-sparc/page.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-sparc/page.h	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.44 1999/06/23 03:53:11 davem Exp $
+/* $Id: page.h,v 1.45 1999/07/03 08:58:05 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -19,7 +19,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
 #include <asm/head.h>       /* for KERNBASE */
 #include <asm/btfixup.h>
 
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.3.9/linux/include/asm-sparc64/asm_offsets.h	Thu May 27 09:55:22 1999
+++ linux/include/asm-sparc64/asm_offsets.h	Sun Jul  4 09:53:12 1999
@@ -197,47 +197,49 @@
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x00000028
 #define ASIZ_mm_mmap_sem	0x00000038
-#define AOFF_mm_context	0x00000060
+#define AOFF_mm_page_table_lock	0x00000060
+#define ASIZ_mm_page_table_lock	0x00000001
+#define AOFF_mm_context	0x00000068
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000068
+#define AOFF_mm_start_code	0x00000070
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000070
+#define AOFF_mm_end_code	0x00000078
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000078
+#define AOFF_mm_start_data	0x00000080
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000080
+#define AOFF_mm_end_data	0x00000088
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000088
+#define AOFF_mm_start_brk	0x00000090
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000090
+#define AOFF_mm_brk	0x00000098
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x00000098
+#define AOFF_mm_start_stack	0x000000a0
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000a0
+#define AOFF_mm_arg_start	0x000000a8
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000a8
+#define AOFF_mm_arg_end	0x000000b0
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000b0
+#define AOFF_mm_env_start	0x000000b8
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000b8
+#define AOFF_mm_env_end	0x000000c0
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000c0
+#define AOFF_mm_rss	0x000000c8
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000c8
+#define AOFF_mm_total_vm	0x000000d0
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000d0
+#define AOFF_mm_locked_vm	0x000000d8
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000d8
+#define AOFF_mm_def_flags	0x000000e0
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000e0
+#define AOFF_mm_cpu_vm_mask	0x000000e8
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000e8
+#define AOFF_mm_swap_cnt	0x000000f0
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x000000f0
+#define AOFF_mm_swap_address	0x000000f8
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x000000f8
+#define AOFF_mm_segments	0x00000100
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000100
+#define ASIZ_mm	0x00000108
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
@@ -481,47 +483,49 @@
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x00000028
 #define ASIZ_mm_mmap_sem	0x00000038
-#define AOFF_mm_context	0x00000060
+#define AOFF_mm_page_table_lock	0x00000060
+#define ASIZ_mm_page_table_lock	0x00000001
+#define AOFF_mm_context	0x00000068
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000068
+#define AOFF_mm_start_code	0x00000070
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000070
+#define AOFF_mm_end_code	0x00000078
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000078
+#define AOFF_mm_start_data	0x00000080
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000080
+#define AOFF_mm_end_data	0x00000088
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000088
+#define AOFF_mm_start_brk	0x00000090
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000090
+#define AOFF_mm_brk	0x00000098
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x00000098
+#define AOFF_mm_start_stack	0x000000a0
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000a0
+#define AOFF_mm_arg_start	0x000000a8
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000a8
+#define AOFF_mm_arg_end	0x000000b0
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000b0
+#define AOFF_mm_env_start	0x000000b8
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000b8
+#define AOFF_mm_env_end	0x000000c0
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000c0
+#define AOFF_mm_rss	0x000000c8
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000c8
+#define AOFF_mm_total_vm	0x000000d0
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000d0
+#define AOFF_mm_locked_vm	0x000000d8
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000d8
+#define AOFF_mm_def_flags	0x000000e0
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000e0
+#define AOFF_mm_cpu_vm_mask	0x000000e8
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000e8
+#define AOFF_mm_swap_cnt	0x000000f0
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x000000f0
+#define AOFF_mm_swap_address	0x000000f8
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x000000f8
+#define AOFF_mm_segments	0x00000100
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000100
+#define ASIZ_mm	0x00000108
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
@@ -763,47 +767,49 @@
 #define ASIZ_mm_map_count	0x00000004
 #define AOFF_mm_mmap_sem	0x00000028
 #define ASIZ_mm_mmap_sem	0x00000040
-#define AOFF_mm_context	0x00000068
+#define AOFF_mm_page_table_lock	0x00000068
+#define ASIZ_mm_page_table_lock	0x0000000c
+#define AOFF_mm_context	0x00000078
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000070
+#define AOFF_mm_start_code	0x00000080
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000078
+#define AOFF_mm_end_code	0x00000088
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000080
+#define AOFF_mm_start_data	0x00000090
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000088
+#define AOFF_mm_end_data	0x00000098
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000090
+#define AOFF_mm_start_brk	0x000000a0
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000098
+#define AOFF_mm_brk	0x000000a8
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x000000a0
+#define AOFF_mm_start_stack	0x000000b0
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000a8
+#define AOFF_mm_arg_start	0x000000b8
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000b0
+#define AOFF_mm_arg_end	0x000000c0
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000b8
+#define AOFF_mm_env_start	0x000000c8
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000c0
+#define AOFF_mm_env_end	0x000000d0
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000c8
+#define AOFF_mm_rss	0x000000d8
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000d0
+#define AOFF_mm_total_vm	0x000000e0
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000d8
+#define AOFF_mm_locked_vm	0x000000e8
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000e0
+#define AOFF_mm_def_flags	0x000000f0
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000e8
+#define AOFF_mm_cpu_vm_mask	0x000000f8
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000f0
+#define AOFF_mm_swap_cnt	0x00000100
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x000000f8
+#define AOFF_mm_swap_address	0x00000108
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000100
+#define AOFF_mm_segments	0x00000110
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000108
+#define ASIZ_mm	0x00000118
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h
--- v2.3.9/linux/include/asm-sparc64/atomic.h	Sat Aug 16 09:51:10 1997
+++ linux/include/asm-sparc64/atomic.h	Sun Jul  4 09:53:12 1999
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.18 1997/08/07 03:38:31 davem Exp $
+/* $Id: atomic.h,v 1.19 1999/07/03 22:11:17 davem Exp $
  * atomic.h: Thankfully the V9 is at least reasonable for this
  *           stuff.
  *
@@ -20,66 +20,34 @@
 #define atomic_read(v)		((v)->counter)
 #define atomic_set(v, i)	(((v)->counter) = i)
 
-extern __inline__ void atomic_add(int i, atomic_t *v)
-{
-	__asm__ __volatile__("
-1:	lduw		[%1], %%g5
-	add		%%g5, %0, %%g7
-	cas		[%1], %%g5, %%g7
-	sub		%%g5, %%g7, %%g5
-	brnz,pn		%%g5, 1b
-	 nop"
-	: /* No outputs */
-	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g5", "g7", "memory");
-}
-
-extern __inline__ void atomic_sub(int i, atomic_t *v)
-{
-	__asm__ __volatile__("
-1:	lduw		[%1], %%g5
-	sub		%%g5, %0, %%g7
-	cas		[%1], %%g5, %%g7
-	sub		%%g5, %%g7, %%g5
-	brnz,pn		%%g5, 1b
-	 nop"
-	: /* No outputs */
-	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g5", "g7", "memory");
-}
-
-/* Same as above, but return the result value. */
-extern __inline__ int atomic_add_return(int i, atomic_t *v)
-{
-	unsigned long oldval;
-	__asm__ __volatile__("
-1:	lduw		[%2], %%g5
-	add		%%g5, %1, %%g7
-	cas		[%2], %%g5, %%g7
-	sub		%%g5, %%g7, %%g5
-	brnz,pn		%%g5, 1b
-	 add		%%g7, %1, %0"
-	: "=&r" (oldval)
-	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g5", "g7", "memory");
-	return (int)oldval;
-}
-
-extern __inline__ int atomic_sub_return(int i, atomic_t *v)
-{
-	unsigned long oldval;
-	__asm__ __volatile__("
-1:	lduw		[%2], %%g5
-	sub		%%g5, %1, %%g7
-	cas		[%2], %%g5, %%g7
-	sub		%%g5, %%g7, %%g5
-	brnz,pn		%%g5, 1b
-	 sub		%%g7, %1, %0"
-	: "=&r" (oldval)
-	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g5", "g7", "memory");
-	return (int)oldval;
-}
+#define atomic_add_return(__i, __v) \
+({	register atomic_t *__V asm("g1"); \
+	register int __I asm("g2"); \
+	__V = (__v); __I = (__i); \
+	__asm__ __volatile__("sethi	%%hi(__atomic_add), %%g3\n\t" \
+			     "jmpl	%%g3 + %%lo(__atomic_add), %%g3\n\t" \
+			     " nop\n1:" \
+			     : "=&r" (__I) \
+			     : "0" (__I), "r" (__V) \
+			     : "g3", "g5", "g7", "cc", "memory"); \
+	__I; \
+})
+
+#define atomic_sub_return(__i, __v) \
+({	register atomic_t *__V asm("g1"); \
+	register int __I asm("g2"); \
+	__V = (__v); __I = (__i); \
+	__asm__ __volatile__("sethi	%%hi(__atomic_sub), %%g3\n\t" \
+			     "jmpl	%%g3 + %%lo(__atomic_sub), %%g3\n\t" \
+			     " nop\n1:" \
+			     : "=&r" (__I) \
+			     : "0" (__I), "r" (__V) \
+			     : "g3", "g5", "g7", "cc", "memory"); \
+	__I; \
+})
+
+#define atomic_add(i, v) atomic_add_return(i, v)
+#define atomic_sub(i, v) atomic_sub_return(i, v)
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc64/audioio.h linux/include/asm-sparc64/audioio.h
--- v2.3.9/linux/include/asm-sparc64/audioio.h	Wed May 12 08:41:15 1999
+++ linux/include/asm-sparc64/audioio.h	Mon Jul  5 20:35:18 1999
@@ -237,7 +237,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
diff -u --recursive --new-file v2.3.9/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.3.9/linux/include/asm-sparc64/spinlock.h	Thu Jun 17 01:08:50 1999
+++ linux/include/asm-sparc64/spinlock.h	Sun Jul  4 09:53:12 1999
@@ -42,7 +42,7 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-typedef unsigned long rwlock_t;
+typedef unsigned int rwlock_t;
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 
 #define read_lock(lock)		do { } while(0)
@@ -255,90 +255,44 @@
 
 #ifndef SPIN_LOCK_DEBUG
 
-typedef unsigned long rwlock_t;
+typedef unsigned int rwlock_t;
 #define RW_LOCK_UNLOCKED	0
 
-extern __inline__ void read_lock(rwlock_t *rw)
-{
-	__asm__ __volatile__("
-1:	ldx		[%0], %%g5
-	brlz,pn		%%g5, 2f
-4:	 add		%%g5, 1, %%g7
-	casx		[%0], %%g5, %%g7
-	cmp		%%g5, %%g7
-	bne,pn		%%xcc, 1b
-	 membar		#StoreLoad | #StoreStore
-	.subsection	2
-2:	ldx		[%0], %%g5
-	brlz,pt		%%g5, 2b
-	 membar		#LoadLoad
-	b,a,pt		%%xcc, 4b
-	.previous
-"	: /* no outputs */
-	: "r" (rw)
-	: "g5", "g7", "cc", "memory");
-}
-
-extern __inline__ void read_unlock(rwlock_t *rw)
-{
-	__asm__ __volatile__("
-1:	ldx		[%0], %%g5
-	sub		%%g5, 1, %%g7
-	casx		[%0], %%g5, %%g7
-	cmp		%%g5, %%g7
-	bne,pn		%%xcc, 1b
-	 membar		#StoreLoad | #StoreStore
-"	: /* no outputs */
-	: "r" (rw)
-	: "g5", "g7", "cc", "memory");
-}
-
-extern __inline__ void write_lock(rwlock_t *rw)
-{
-	__asm__ __volatile__("
-	sethi		%%uhi(0x8000000000000000), %%g3
-	sllx		%%g3, 32, %%g3
-1:	ldx		[%0], %%g5
-	brlz,pn		%%g5, 5f
-4:	 or		%%g5, %%g3, %%g7
-	casx		[%0], %%g5, %%g7
-	cmp		%%g5, %%g7
-	bne,pn		%%xcc, 1b
-	 andncc		%%g7, %%g3, %%g0
-	bne,pn		%%xcc, 7f
-	 membar		#StoreLoad | #StoreStore
-	.subsection	2
-7:	ldx		[%0], %%g5
-	andn		%%g5, %%g3, %%g7
-	casx		[%0], %%g5, %%g7
-	cmp		%%g5, %%g7
-	bne,pn		%%xcc, 7b
-	 membar		#StoreLoad | #StoreStore
-5:	ldx		[%0], %%g5
-	brnz,pt		%%g5, 5b
-	 membar		#LoadLoad
-	b,a,pt		%%xcc, 4b
-	.previous
-"	: /* no outputs */
-	: "r" (rw)
-	: "g3", "g5", "g7", "memory", "cc");
-}
-
-extern __inline__ void write_unlock(rwlock_t *rw)
-{
-	__asm__ __volatile__("
-	sethi		%%uhi(0x8000000000000000), %%g3
-	sllx		%%g3, 32, %%g3
-1:	ldx		[%0], %%g5
-	andn		%%g5, %%g3, %%g7
-	casx		[%0], %%g5, %%g7
-	cmp		%%g5, %%g7
-	bne,pn		%%xcc, 1b
-	 membar		#StoreLoad | #StoreStore
-"	: /* no outputs */
-	: "r" (rw)
-	: "g3", "g5", "g7", "memory", "cc");
-}
+#define read_lock(__rw_lck) \
+do {	register rwlock_t *__X asm("g1"); \
+	__asm__ __volatile__("sethi	%%hi(__read_lock), %%g3\n\t" \
+			     "jmpl	%%g3 + %%lo(__read_lock), %%g3\n\t" \
+			     " nop\n1:" \
+	: : "r" (__X = (__rw_lck)) \
+	  : "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
+
+#define read_unlock(__rw_lck) \
+do {	register rwlock_t *__X asm("g1"); \
+	__asm__ __volatile__("sethi	%%hi(__read_unlock), %%g3\n\t" \
+			     "jmpl	%%g3 + %%lo(__read_unlock), %%g3\n\t" \
+			     " nop\n1:" \
+	: : "r" (__X = (__rw_lck)) \
+	  : "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
+
+#define write_lock(__rw_lck) \
+do {	register rwlock_t *__X asm("g1"); \
+	__asm__ __volatile__("sethi	%%hi(__write_lock), %%g3\n\t" \
+			     "jmpl	%%g3 + %%lo(__write_lock), %%g3\n\t" \
+			     " nop\n1:" \
+	: : "r" (__X = (__rw_lck)) \
+	  : "g2", "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
+
+#define write_unlock(__rw_lck) \
+do {	register rwlock_t *__X asm("g1"); \
+	__asm__ __volatile__("sethi	%%hi(__write_unlock), %%g3\n\t" \
+			     "jmpl	%%g3 + %%lo(__write_unlock), %%g3\n\t" \
+			     " nop\n1:" \
+	: : "r" (__X = (__rw_lck)) \
+	  : "g2", "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
 
 #define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
 #define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
diff -u --recursive --new-file v2.3.9/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.9/linux/include/linux/blk.h	Tue Jun 22 14:42:32 1999
+++ linux/include/linux/blk.h	Wed Jul  7 09:22:27 1999
@@ -359,6 +359,24 @@
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == I2O_MAJOR)
+
+#define DEVICE_NAME "I2O block"
+#define DEVICE_REQUEST do_i2ob_request
+#define DEVICE_NR(device) (MINOR(device)>>4)
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
+
+#define DEVICE_NAME "ida"
+#define DEVICE_INTR do_ida
+#define TIMEOUT_VALUE (25*HZ)
+#define DEVICE_REQUEST do_ida_request0
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #endif /* MAJOR_NR == whatever */
 
 #if (MAJOR_NR != SCSI_TAPE_MAJOR)
@@ -435,7 +453,7 @@
 
 #ifndef LOCAL_END_REQUEST	/* If we have our own end_request, we do not want to include this mess */
 
-#if ! SCSI_BLK_MAJOR(MAJOR_NR)
+#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR)
 
 static void end_request(int uptodate) {
 	struct request *req = CURRENT;
diff -u --recursive --new-file v2.3.9/linux/include/linux/coda.h linux/include/linux/coda.h
--- v2.3.9/linux/include/linux/coda.h	Mon Jan 25 10:28:35 1999
+++ linux/include/linux/coda.h	Tue Jul  6 19:08:33 1999
@@ -100,22 +100,35 @@
 
 #if defined(__linux__)
 #define cdev_t u_quad_t
+#ifndef __KERNEL__
 #if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2)
 #define _UQUAD_T_ 1
 typedef unsigned long long u_quad_t;
 #endif
+#else /*__KERNEL__ */
+typedef unsigned long long u_quad_t;
+#endif /* __KERNEL__ */
 #else
 #define cdev_t dev_t
 #endif
 
 #ifdef __CYGWIN32__
-typedef unsigned char u_int8_t;
 struct timespec {
         time_t  tv_sec;         /* seconds */
         long    tv_nsec;        /* nanoseconds */
 };
 #endif
 
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+typedef signed char	      int8_t;
+typedef unsigned char	    u_int8_t;
+typedef short		     int16_t;
+typedef unsigned short	   u_int16_t;
+typedef int		     int32_t;
+typedef unsigned int	   u_int32_t;
+#endif
+
 
 /*
  * Cfs constants
@@ -151,8 +164,8 @@
 struct venus_dirent {
         unsigned long	d_fileno;		/* file number of entry */
         unsigned short	d_reclen;		/* length of this record */
-        char 		d_type;			/* file type, see below */
-        char		d_namlen;		/* length of string in d_name */
+        unsigned char 	d_type;			/* file type, see below */
+        unsigned char	d_namlen;		/* length of string in d_name */
         char		d_name[CODA_MAXNAMLEN + 1];/* name must be no longer than this */
 };
 #undef DIRSIZ
@@ -215,11 +228,6 @@
 #endif
 
 
-#ifndef __BIT_TYPES_DEFINED__
-#define u_int32_t unsigned int
-#endif
-
-
 #ifndef _VUID_T_
 #define _VUID_T_
 typedef u_int32_t vuid_t;
@@ -229,12 +237,8 @@
 #ifndef _CODACRED_T_
 #define _CODACRED_T_
 struct coda_cred {
-	vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid;
-	vgid_t cr_groupid,     cr_egid, cr_sgid, cr_fsgid;
-#if   defined(CODA_SUPPORTS_SUPPLEMENTARY_GROUPS)
-	int    cr_nsupgps;
-	vgid_t cr_supgps[NGROUPS];
-#endif        /* defined(CODA_SUPPORTS_SUPPLEMENTARY_GROUPS) */
+    vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, efftve, set, fs uid*/
+    vgid_t cr_groupid,     cr_egid, cr_sgid, cr_fsgid; /* same for groups */
 };
 #endif 
 
@@ -246,7 +250,7 @@
 enum coda_vtype	{ C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD };
 
 struct coda_vattr {
-	int     	va_type;	/* vnode type (for create) */
+	long     	va_type;	/* vnode type (for create) */
 	u_short		va_mode;	/* files access mode and type */
 	short		va_nlink;	/* number of references to file */
 	vuid_t		va_uid;		/* owner user id */
@@ -266,6 +270,15 @@
 
 #endif 
 
+/* structure used by CODA_STATFS for getting cache information from venus */
+struct coda_statfs {
+    int32_t f_blocks;
+    int32_t f_bfree;
+    int32_t f_bavail;
+    int32_t f_files;
+    int32_t f_ffree;
+};
+
 /*
  * Kernel <--> Venus communications.
  */
@@ -301,7 +314,8 @@
 #define CODA_OPEN_BY_PATH 31
 #define CODA_RESOLVE     32
 #define CODA_REINTEGRATE 33
-#define CODA_NCALLS 34
+#define CODA_STATFS	 34
+#define CODA_NCALLS 35
 
 #define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID)
 
@@ -675,6 +689,16 @@
 	int path;
 };
 
+/* coda_statfs: NO_IN */
+struct coda_statfs_in {
+    struct coda_in_hdr in;
+};
+
+struct coda_statfs_out {
+    struct coda_out_hdr oh;
+    struct coda_statfs stat;
+};
+
 /* 
  * Occasionally, we don't cache the fid returned by CODA_LOOKUP. 
  * For instance, if the fid is inconsistent. 
@@ -704,7 +728,8 @@
     struct coda_inactive_in coda_inactive;
     struct coda_vget_in coda_vget;
     struct coda_rdwr_in coda_rdwr;
-	struct coda_open_by_path_in coda_open_by_path;
+    struct coda_open_by_path_in coda_open_by_path;
+    struct coda_statfs_in coda_statfs;
 };
 
 union outputArgs {
@@ -726,7 +751,8 @@
     struct coda_purgefid_out coda_purgefid;
     struct coda_rdwr_out coda_rdwr;
     struct coda_replace_out coda_replace;
-	struct coda_open_by_path_out coda_open_by_path;
+    struct coda_open_by_path_out coda_open_by_path;
+    struct coda_statfs_out coda_statfs;
 };    
 
 union coda_downcalls {
@@ -752,20 +778,11 @@
         short out_size;         /* Maximum size of output buffer, <= 2K */
 };
 
-#if defined(__CYGWIN32__) || defined(DJGPP)
 struct PioctlData {
-	unsigned long cmd;
         const char *path;
         int follow;
         struct ViceIoctl vi;
 };
-#else
-struct PioctlData {
-        const char *path;
-        int follow;
-        struct ViceIoctl vi;
-};
-#endif
 
 #define	CODA_CONTROL		".CONTROL"
 #define CODA_CONTROLLEN           8
diff -u --recursive --new-file v2.3.9/linux/include/linux/coda_proc.h linux/include/linux/coda_proc.h
--- v2.3.9/linux/include/linux/coda_proc.h	Mon May  4 17:09:22 1998
+++ linux/include/linux/coda_proc.h	Tue Jul  6 19:08:33 1999
@@ -98,6 +98,7 @@
 extern struct coda_vfs_stats		coda_vfs_stat;
 extern struct coda_permission_stats	coda_permission_stat;
 extern struct coda_cache_inv_stats	coda_cache_inv_stat;
+extern int				coda_upcall_timestamping;
 
 /* reset statistics to 0 */
 void reset_coda_vfs_stats( void );
diff -u --recursive --new-file v2.3.9/linux/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h
--- v2.3.9/linux/include/linux/coda_psdev.h	Wed May 12 08:41:15 1999
+++ linux/include/linux/coda_psdev.h	Tue Jul  6 19:08:33 1999
@@ -80,6 +80,7 @@
 		 unsigned int cmd, struct PioctlData *data);
 int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
 int venus_fsync(struct super_block *sb, struct ViceFid *fid);
+int venus_statfs(struct super_block *sb, struct statfs *sfs);
 
 
 /* messages between coda filesystem in kernel and Venus */
diff -u --recursive --new-file v2.3.9/linux/include/linux/cyclades.h linux/include/linux/cyclades.h
--- v2.3.9/linux/include/linux/cyclades.h	Mon May 24 22:38:07 1999
+++ linux/include/linux/cyclades.h	Tue Jul  6 19:05:48 1999
@@ -517,7 +517,7 @@
     int num_chips;	/* 0 if card absent, -1 if Z/PCI, else Y */
     int first_line;	/* minor number of first channel on card */
     int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
-    int	inact_ctrl;	/* FW Inactivity control - 0 disabled, 1 enabled */
+    int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
 };
 
 struct cyclades_chip {
diff -u --recursive --new-file v2.3.9/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.9/linux/include/linux/file.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/file.h	Sun Jul  4 10:18:52 1999
@@ -5,7 +5,8 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-extern void __fput(struct file *);
+extern void __fput(struct file *);	/* goner? */
+extern void _fput(struct file *);
 
 /*
  * Check whether the specified task has the fd open. Since the task
@@ -15,7 +16,7 @@
 {
 	struct file * file = NULL;
 
-	if (p->files && fd < p->files->max_fds)
+	if (fd < p->files->max_fds)
 		file = p->files->fd[fd];
 	return file;
 }
@@ -28,10 +29,17 @@
 	struct file * file = NULL;
 	struct files_struct *files = current->files;
 
-	read_lock(&files->file_lock);
 	if (fd < files->max_fds)
 		file = files->fd[fd];
-	read_unlock(&files->file_lock);
+	return file;
+}
+
+extern inline struct file * frip(unsigned int fd)
+{
+	struct file * file = NULL;
+
+	if (fd < current->files->max_fds)
+		file = xchg(&current->files->fd[fd], NULL);
 	return file;
 }
 
@@ -41,11 +49,9 @@
 	struct files_struct *files = current->files;
 
 	read_lock(&files->file_lock);
-	if (fd < files->max_fds) {
-		file = files->fd[fd];
-		if (file)
-			atomic_inc(&file->f_count);
-	}
+	file = fcheck(fd);
+	if (file)
+		get_file(file);
 	read_unlock(&files->file_lock);
 	return file;
 }
@@ -78,7 +84,11 @@
  * I suspect there are many other similar "optimizations" across the
  * kernel...
  */
-extern void fput(struct file *); 
+extern inline void fput(struct file * file)
+{
+	if (atomic_dec_and_test(&file->f_count))
+		_fput(file);
+}
 extern void put_filp(struct file *);
 
 #endif /* __LINUX_FILE_H */
diff -u --recursive --new-file v2.3.9/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.9/linux/include/linux/fs.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/fs.h	Wed Jul  7 09:20:40 1999
@@ -346,6 +346,7 @@
 	struct file_lock	*i_flock;
 	struct vm_area_struct	*i_mmap;
 	struct page		*i_pages;
+	spinlock_t		i_shared_lock;
 	struct dquot		*i_dquot[MAXQUOTAS];
 	struct pipe_inode_info	*i_pipe;
 
@@ -354,7 +355,7 @@
 	unsigned int		i_flags;
 	unsigned char		i_sock;
 
-	int			i_writecount;
+	atomic_t		i_writecount;
 	unsigned int		i_attr_flags;
 	__u32			i_generation;
 	union {
@@ -400,7 +401,7 @@
 };
 
 struct file {
-	struct file		*f_next, **f_pprev;
+	struct list_head	f_list;
 	struct dentry		*f_dentry;
 	struct file_operations	*f_op;
 	atomic_t		f_count;
@@ -417,6 +418,12 @@
 	/* needed for tty driver, and maybe others */
 	void			*private_data;
 };
+extern spinlock_t files_lock;
+#define file_list_lock() spin_lock(&files_lock);
+#define file_list_unlock() spin_unlock(&files_lock);
+
+#define get_file(x)	atomic_inc(&(x)->f_count)
+#define file_count(x)	atomic_read(&(x)->f_count)
 
 extern int init_private_file(struct file *, struct dentry *, int);
 
@@ -524,6 +531,7 @@
 	short int		s_ibasket_count;
 	short int		s_ibasket_max;
 	struct list_head	s_dirty;	/* dirty inodes */
+	struct list_head	s_files;
 
 	union {
 		struct minix_sb_info	minix_sb;
@@ -657,6 +665,10 @@
 extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
 
+/* Return value for VFS lock functions - tells locks.c to lock conventionally
+ * REALLY kosha for root NFS and nfs_lock
+ */ 
+#define LOCK_USE_CLNT 1
 
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
@@ -664,29 +676,27 @@
 extern int locks_mandatory_locked(struct inode *);
 extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
 
-extern inline int locks_verify_locked(struct inode *inode)
+/*
+ * Candidates for mandatory locking have the setgid bit set
+ * but no group execute bit -  an otherwise meaningless combination.
+ */
+#define MANDATORY_LOCK(inode) \
+	(IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+
+static inline int locks_verify_locked(struct inode *inode)
 {
-	/* Candidates for mandatory locking have the setgid bit set
-	 * but no group execute bit -  an otherwise meaningless combination.
-	 */
-	if (IS_MANDLOCK(inode) &&
-	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-		return (locks_mandatory_locked(inode));
-	return (0);
+	if (MANDATORY_LOCK(inode))
+		return locks_mandatory_locked(inode);
+	return 0;
 }
 
 extern inline int locks_verify_area(int read_write, struct inode *inode,
 				    struct file *filp, loff_t offset,
 				    size_t count)
 {
-	/* Candidates for mandatory locking have the setgid bit set
-	 * but no group execute bit -  an otherwise meaningless combination.
-	 */
-	if (IS_MANDLOCK(inode) &&
-	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-		return (locks_mandatory_area(read_write, inode, filp, offset,
-					     count));
-	return (0);
+	if (inode->i_flock && MANDATORY_LOCK(inode))
+		return locks_mandatory_area(read_write, inode, filp, offset, count);
+	return 0;
 }
 
 
@@ -744,8 +754,6 @@
 extern int fs_may_remount_ro(struct super_block *);
 extern int fs_may_mount(kdev_t);
 
-extern struct file *inuse_filps;
-
 extern int try_to_free_buffers(struct page *);
 extern void refile_buffer(struct buffer_head * buf);
 
@@ -854,6 +862,8 @@
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
+extern void file_move(struct file *f, struct list_head *list);
+extern void file_moveto(struct file *new, struct file *old);
 extern struct buffer_head * get_hash_table(kdev_t, int, int);
 extern struct buffer_head * getblk(kdev_t, int, int);
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
@@ -916,10 +926,6 @@
 
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern void inode_setattr(struct inode *, struct iattr *);
-
-/* kludge to get SCSI modules working */
-#include <linux/minix_fs.h>
-#include <linux/minix_fs_sb.h>
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.9/linux/include/linux/i2c.h linux/include/linux/i2c.h
--- v2.3.9/linux/include/linux/i2c.h	Tue Jun 22 14:41:40 1999
+++ linux/include/linux/i2c.h	Wed Jul  7 09:20:39 1999
@@ -32,13 +32,15 @@
 struct i2c_driver;
 struct i2c_device;
 
-#define I2C_DRIVERID_MSP3400     1
-#define I2C_DRIVERID_TUNER       2
-#define I2C_DRIVERID_VIDEOTEXT	 3
+#define I2C_DRIVERID_MSP3400    	 1
+#define I2C_DRIVERID_TUNER      	 2
+#define I2C_DRIVERID_VIDEOTEXT		 3
+#define I2C_DRIVERID_VIDEODECODER	 4
+#define I2C_DRIVERID_VIDEOENCODER	 5
 
 #define I2C_BUSID_BT848		1	/* I2C bus on a BT848 */
 #define I2C_BUSID_PARPORT	2	/* Bit banging on a parallel port */
-
+#define I2C_BUSID_BUZ		3
 /*
  * struct for a driver for a i2c chip (tuner, soundprocessor,
  * videotext, ... ).
diff -u --recursive --new-file v2.3.9/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.9/linux/include/linux/i2o.h	Wed Jun  2 14:40:22 1999
+++ linux/include/linux/i2o.h	Mon Jul  5 20:09:40 1999
@@ -24,9 +24,6 @@
  * message structures
  */
 
-#define    TID_SZ                                  12
-#define    FUNCTION_SZ                             8
-
 struct i2o_message
 {
 	u32	version_size;
@@ -35,6 +32,110 @@
 	/* List follows */
 };
 
+/**************************************************************************
+ * HRT related constants and structures
+ **************************************************************************/
+#define I2O_BUS_LOCAL	0
+#define I2O_BUS_ISA	1
+#define I2O_BUS_EISA	2
+#define I2O_BUS_MCA	3
+#define I2O_BUS_PCI	4
+#define I2O_BUS_PCMCIA	5
+#define I2O_BUS_NUBUS	6
+#define I2O_BUS_CARDBUS	7
+#define I2O_BUS_UNKNOWN	0x80
+
+typedef struct _i2o_pci_bus {
+	u8 PciFunctionNumber;
+	u8 PciDeviceNumber;
+	u8 PciBusNumber;
+	u8 reserved;
+	u16 PciVendorID;
+	u16 PciDeviceID;
+} i2o_pci_bus, *pi2o_pci_bus;
+
+typedef struct _i2o_local_bus {
+	u16 LbBaseIOPort;
+	u16 reserved;
+	u32 LbBaseMemoryAddress;
+} i2o_local_bus, *pi2o_local_bus;
+
+typedef struct _i2o_isa_bus {
+	u16 IsaBaseIOPort;
+	u8 CSN;
+	u8 reserved;
+	u32 IsaBaseMemoryAddress;
+} i2o_isa_bus, *pi2o_isa_bus;
+
+typedef struct _i2o_eisa_bus_info {
+	u16 EisaBaseIOPort;
+	u8 reserved;
+	u8 EisaSlotNumber;
+	u32 EisaBaseMemoryAddress;
+} i2o_eisa_bus, *pi2o_eisa_bus;
+
+typedef struct _i2o_mca_bus {
+	u16 McaBaseIOPort;
+	u8 reserved;
+	u8 McaSlotNumber;
+	u32 McaBaseMemoryAddress;
+} i2o_mca_bus, *pi2o_mca_bus;
+
+typedef struct _i2o_other_bus {
+	u16 BaseIOPort;
+	u16 reserved;
+	u32 BaseMemoryAddress;
+} i2o_other_bus, *pi2o_other_bus;
+
+
+typedef struct _i2o_hrt_entry {
+	u32 adapter_id;
+	u32 parent_tid:12;
+	u32 state:4;
+	u32 bus_num:8;
+	u32 bus_type:8;
+	union {
+		i2o_pci_bus pci_bus;
+		i2o_local_bus local_bus;
+		i2o_isa_bus isa_bus;
+		i2o_eisa_bus eisa_bus;
+		i2o_mca_bus mca_bus;
+		i2o_other_bus other_bus;
+	} bus;
+} i2o_hrt_entry, *pi2o_hrt_entry;
+
+typedef struct _i2o_hrt {
+	u16 num_entries;
+	u8 entry_len;
+	u8 hrt_version;
+	u32 change_ind;
+	i2o_hrt_entry hrt_entry[1];
+} i2o_hrt, *pi2o_hrt;
+
+typedef struct _i2o_lct_entry {
+	u32 entry_size:16;
+	u32 tid:12;
+	u32 reserved:4;
+	u32 change_ind;
+	u32 device_flags;
+	u32 class_id;
+	u32 sub_class;
+	u32 user_tid:12;
+	u32 parent_tid:12;
+	u32 bios_info:8;
+	u8 identity_tag[8];
+	u32 event_capabilities;
+} i2o_lct_entry, *pi2o_lct_entry;
+
+typedef struct _i2o_lct {
+	u32 table_size:16;
+	u32 boot_tid:12;
+	u32 lct_ver:4;
+	u32 iop_flags;
+	u32 current_change_ind;
+	i2o_lct_entry lct_entry[1];
+} i2o_lct, *pi2o_lct;
+
 
 /*
  *	Each I2O device entity has one or more of these. There is one
@@ -85,6 +186,8 @@
 	volatile u32 *post_port;		/* Messaging ports */
 	volatile u32 *reply_port;
 	volatile u32 *irq_mask;			/* Interrupt port */
+	u32 *lct;
+	u32 *hrt;
 	u32 mem_offset;				/* MFA offset */
 	u32 mem_phys;				/* MFA physical */
 	u32 priv_mem;
@@ -185,18 +288,22 @@
 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_query_scalar(struct i2o_controller *, int, int, int, int, void *,
-			    int, int *);
-extern int i2o_params_set(struct i2o_controller *c, int, int, int, int, void *,
-			  int, int *);
 
-extern void i2o_run_queue(struct i2o_controller *);
+extern int i2o_query_scalar(struct i2o_controller *, int, int, int, int, 
+			void *, int, int *);
+extern int i2o_set_scalar(struct i2o_controller *, int, int, int, int, 
+			void *, int, int *);
+
+extern int i2o_query_table(int, struct i2o_controller *, int, int, int, int, 
+			void *, int, void *, int, int *);
+extern int i2o_clear_table(struct i2o_controller *, int, int, int, int *); 
+extern int i2o_row_add_table(struct i2o_controller *, int, int, int, int,
+			void *, int, int *);
+extern int i2o_row_delete_table(struct i2o_controller *, int, int, int, int,
+			void *, int, int *);
 
-extern void i2o_report_status(const char *, const char *, u8, u8, u16);
-extern void report_common_status(u8);
-extern void report_lan_dsc(u16);
-
-extern u32 i2o_wait_message(struct i2o_controller *, char *);
+extern void i2o_run_queue(struct i2o_controller *);
+extern void i2o_report_status(const char *, const char *, u32 *);
 
 extern const char *i2o_get_class_name(int);
 
@@ -278,28 +385,12 @@
 #define    I2O_SNFORMAT_IEEE_REG128                    9
 #define    I2O_SNFORMAT_UNKNOWN2                       0xff
 
-
-/*
- *	"Special" TID assignments
- */
-#define    I2O_IOP_TID                                 0
-#define    I2O_HOST_TID                                1
-
-
 /* Transaction Reply Lists (TRL) Control Word structure */
 
 #define TRL_SINGLE_FIXED_LENGTH		0x00
 #define TRL_SINGLE_VARIABLE_LENGTH	0x40
 #define TRL_MULTIPLE_FIXED_LENGTH	0x80
 
-/* LAN Class specific functions */
-
-#define    LAN_PACKET_SEND			0x3B
-#define    LAN_SDU_SEND				0x3D
-#define    LAN_RECEIVE_POST			0x3E
-#define    LAN_RESET				0x35
-#define    LAN_SUSPEND				0x37
-
 /*
  *	Messaging API values
  */
@@ -468,7 +559,7 @@
 #define I2O_DSC_UNSUPPORTED_VERSION            0x001A
 #define I2O_DSC_DEVICE_BUSY                    0x001B
 #define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
-
+ 
 /* Message header defines for VersionOffset */
 #define I2OVER15	0x0001
 #define I2OVER20	0x0002
@@ -478,7 +569,9 @@
 #define SGL_OFFSET_4    (0x0040 | I2OVERSION)
 #define SGL_OFFSET_5    (0x0050 | I2OVERSION)
 #define SGL_OFFSET_6    (0x0060 | I2OVERSION)
+#define SGL_OFFSET_7    (0x0070 | I2OVERSION)
 #define SGL_OFFSET_8    (0x0080 | I2OVERSION)
+#define SGL_OFFSET_9    (0x0090 | I2OVERSION)
 #define SGL_OFFSET_10   (0x00A0 | I2OVERSION)
 
 #define TRL_OFFSET_5    (0x0050 | I2OVERSION)
@@ -492,9 +585,6 @@
 #define MSG_LAST	0x4000
 #define MSG_REPLY	0x8000
 
-  /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
-#define LAN_MSG_REQST	(MSG_MULTI_TRANS | SGL_OFFSET_4)
-
  /* minimum size msg */
 #define THREE_WORD_MSG_SIZE	0x00030000
 #define FOUR_WORD_MSG_SIZE	0x00040000
@@ -518,7 +608,7 @@
 #define MSG_POOL_SIZE		16384
 
 #define I2O_POST_WAIT_OK	1
-#define I2O_POST_WAIT_TIMEOUT	-1
+#define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.9/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.9/linux/include/linux/ide.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/ide.h	Wed Jul  7 09:51:41 1999
@@ -265,6 +265,7 @@
 #if FAKE_FDISK_FOR_EZDRIVE
 	unsigned remap_0_to_1	: 1;	/* flag: partitioned with ezdrive */
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
+	unsigned ata_flash	: 1;	/* 1=present, 0=default */
 	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
 	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
@@ -388,6 +389,7 @@
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
 	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
+	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
 	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
 	struct pci_dev	*pci_dev;	/* for pci chipsets */
 	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
@@ -696,6 +698,7 @@
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
 
 void ide_delay_50ms (void);
+int ide_config_drive_speed (ide_drive_t *drive, byte speed);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
diff -u --recursive --new-file v2.3.9/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.3.9/linux/include/linux/isdn.h	Sun May 23 10:03:42 1999
+++ linux/include/linux/isdn.h	Thu Jul  1 10:45:57 1999
@@ -398,9 +398,6 @@
 
 #ifdef __KERNEL__
 
-#ifndef STANDALONE
-#include <linux/config.h>
-#endif
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
diff -u --recursive --new-file v2.3.9/linux/include/linux/isdn_timru.h linux/include/linux/isdn_timru.h
--- v2.3.9/linux/include/linux/isdn_timru.h	Sun May 23 10:03:42 1999
+++ linux/include/linux/isdn_timru.h	Wed Dec 31 16:00:00 1969
@@ -1,119 +0,0 @@
-/* isdn_timru.h
- *
- * Linux ISDN subsystem, timeout-rules for network interfaces.
- *
- * Copyright 1997       by Christian Lademann <cal@zls.de>
- * 
- * 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, 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. 
- *
- */
-
-/*
-02.06.97:cal:ISDN_TIMRU_PACKET_NONE def., ISDN_TIMRU_PACKET_* inkr.
-*/
-
-#ifndef __isdn_timru_h__
-#define __isdn_timru_h__
-
-#define	ISDN_TIMRU_PACKET_NONE		0
-#define	ISDN_TIMRU_PACKET_SKB		1
-#define	ISDN_TIMRU_PACKET_PPP		2
-#define	ISDN_TIMRU_PACKET_PPP_NO_HEADER	3
-
-#define	ISDN_TIMRU_BRINGUP		0
-#define	ISDN_TIMRU_KEEPUP_IN		1
-#define	ISDN_TIMRU_KEEPUP_OUT		2
-#define	ISDN_TIMRU_BRINGDOWN		3
-#define	ISDN_TIMRU_NUM_CHECK		4
-
-#define	ISDN_TIMRU_PROTFAM_WILDCARD	0
-#define	ISDN_TIMRU_PROTFAM_IP		1
-#define	ISDN_TIMRU_PROTFAM_PPP		2
-#define	ISDN_TIMRU_PROTFAM_IPX		3
-#define	ISDN_TIMRU_NUM_PROTFAM		4
-
-#define	ISDN_TIMRU_IP_WILDCARD		0
-#define	ISDN_TIMRU_IP_ICMP		1
-#define	ISDN_TIMRU_IP_TCP		2
-#define	ISDN_TIMRU_IP_UDP		3
-
-#define	ISDN_TIMRU_PPP_WILDCARD		0
-#define	ISDN_TIMRU_PPP_IPCP		1
-#define	ISDN_TIMRU_PPP_IPXCP		2
-#define	ISDN_TIMRU_PPP_CCP		3
-#define	ISDN_TIMRU_PPP_LCP		4
-#define	ISDN_TIMRU_PPP_PAP		5
-#define	ISDN_TIMRU_PPP_LQR		6
-#define	ISDN_TIMRU_PPP_CHAP		7
-
-typedef struct {
-	struct in_addr	saddr,		/* Source Address */
-			smask,		/* Source Subnetmask */
-			daddr,		/* Dest. Address */
-			dmask;		/* Dest. Subnetmask */
-	ushort		protocol;	/* TCP, UDP, ... */
-	union {
-		struct {
-			__u16	s_from,	/* Source Port */
-				s_to,
-				d_from,
-				d_to;
-		}		port;
-		struct {
-			__u8	from,	/* ICMP-Type */
-				to;
-		}		type;
-	}		pt;
-}	isdn_timeout_rule_ip;
-
-
-typedef struct {
-	ushort		protocol;	/* IPCP, LCP, ... */
-}	isdn_timeout_rule_ppp;
-
-
-typedef struct isdn_timeout_rule_s {
-	struct isdn_timeout_rule_s	*next,		/* Pointer to next rule */
-					*prev;		/* Pointer to previous rule */
-	ushort				type,		/* BRINGUP, KEEPUP_*, ... */
-					neg;
-	int				timeout;	/* Timeout value */
-	ushort				protfam;	/* IP, IPX, PPP, ... */
-	union {
-		isdn_timeout_rule_ip	ip;	/* IP-Rule */
-		isdn_timeout_rule_ppp	ppp;	/* PPP-Rule */
-	}				rule;	/* Prot.-specific rule */
-}	isdn_timeout_rule;
-
-
-typedef struct {
-	char			name [9];	/* Interface */
-	int			where,		/* 0/1: add to start/end of list, -1: handle default */
-				type,
-				protfam,
-				index,
-				defval;
-	isdn_timeout_rule	rule;		/* Rule */
-}	isdn_ioctl_timeout_rule;
-
-#ifdef __KERNEL__
-extern int	isdn_net_recalc_timeout(int, int, struct device *, void *, ulong);
-extern int	isdn_timru_alloc_timeout_rules(struct device *);
-extern int	isdn_timru_ioctl_add_rule(isdn_ioctl_timeout_rule *);
-extern int	isdn_timru_ioctl_del_rule(isdn_ioctl_timeout_rule *);
-extern int	isdn_timru_ioctl_get_rule(isdn_ioctl_timeout_rule *);
-#endif /* __KERNEL__ */
-
-#endif /* __isdn_timru_h__ */
diff -u --recursive --new-file v2.3.9/linux/include/linux/lp.h linux/include/linux/lp.h
--- v2.3.9/linux/include/linux/lp.h	Sat May 22 12:42:27 1999
+++ linux/include/linux/lp.h	Thu Jul  1 14:22:57 1999
@@ -21,7 +21,12 @@
 #define LP_ABORT 0x0040
 #define LP_CAREFUL 0x0080 /* obsoleted -arca */
 #define LP_ABORTOPEN 0x0100
-#define	LP_TRUST_IRQ 0x0200
+
+#define LP_TRUST_IRQ_  0x0200 /* obsolete */
+#define LP_NO_REVERSE  0x0400 /* No reverse mode available. */
+#define LP_DATA_AVAIL  0x0800 /* Data is available. */
+#define LP_HAVE_PORT_BIT   12 /* (0x1000) Port is claimed. */
+#define LP_PORT_BUSY   (1<<13) /* Reading or writing. */
 
 /* timeout for each character.  This is relative to bus cycles -- it
  * is the count in a busy loop.  THIS IS THE VALUE TO CHANGE if you
@@ -72,7 +77,6 @@
 #define LPGETSTATS  0x060d  /* get statistics (struct lp_stats) */
 #endif
 #define LPGETFLAGS  0x060e  /* get status flags */
-#define LPTRUSTIRQ  0x060f  /* set/unset the LP_TRUST_IRQ flag */
 
 /* timeout for printk'ing a timeout, in jiffies (100ths of a second).
    This is also used for re-checking error conditions if LP_ABORT is
@@ -98,7 +102,7 @@
 #ifdef LP_STATS
 #define LP_STAT(minor)	lp_table[(minor)].stats		/* statistics area */
 #endif
-#define LP_BUFFER_SIZE 256
+#define LP_BUFFER_SIZE PAGE_SIZE
 
 #define LP_BASE(x)	lp_table[(x)].dev->port->base
 
@@ -125,10 +129,10 @@
 	unsigned int runchars;
 	struct lp_stats stats;
 #endif
-	wait_queue_head_t wait_q;
+	wait_queue_head_t waitq;
 	unsigned int last_error;
-	volatile unsigned int irq_detected:1;
-	volatile unsigned int irq_missed:1;
+	struct semaphore port_mutex;
+	wait_queue_head_t dataq;
 };
 
 /*
@@ -173,9 +177,6 @@
  * It is used only in the lp_init() and lp_reset() routine.
  */
 #define LP_DELAY 	50
-
-#define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE)
-#define LP_PREEMPTED(minor) (lp_table[(minor)].dev->port->waithead != NULL)
 
 /*
  * function prototypes
diff -u --recursive --new-file v2.3.9/linux/include/linux/major.h linux/include/linux/major.h
--- v2.3.9/linux/include/linux/major.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/major.h	Mon Jul  5 19:52:52 1999
@@ -92,8 +92,21 @@
 #define SCSI_DISK7_MAJOR	71
 
 
+#define LVM_BLK_MAJOR	58	/* Logical Volume Manager */
+
+#define COMPAQ_SMART2_MAJOR	72
+#define COMPAQ_SMART2_MAJOR1	73
+#define COMPAQ_SMART2_MAJOR2	74
+#define COMPAQ_SMART2_MAJOR3	75
+#define COMPAQ_SMART2_MAJOR4	76
+#define COMPAQ_SMART2_MAJOR5	77
+#define COMPAQ_SMART2_MAJOR6	78
+#define COMPAQ_SMART2_MAJOR7	79
+
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
+
+#define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
 
 #define I2O_MAJOR		80	/* 80->87 */
 
diff -u --recursive --new-file v2.3.9/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.9/linux/include/linux/mm.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/mm.h	Wed Jul  7 09:20:45 1999
@@ -106,7 +106,6 @@
 	unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
 		unsigned long page);
 	int (*swapout)(struct vm_area_struct *, struct page *);
-	pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
 };
 
 /*
@@ -316,7 +315,10 @@
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
-extern void make_pages_present(unsigned long addr, unsigned long end);
+extern int make_pages_present(unsigned long addr, unsigned long end);
+extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
+extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
+extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
 
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
diff -u --recursive --new-file v2.3.9/linux/include/linux/mount.h linux/include/linux/mount.h
--- v2.3.9/linux/include/linux/mount.h	Sun Aug  9 12:25:12 1998
+++ linux/include/linux/mount.h	Tue Jul  6 10:18:15 1999
@@ -21,7 +21,7 @@
 	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
 	time_t inode_expire[MAXQUOTAS];		/* expiretime for inode-quota */
 	time_t block_expire[MAXQUOTAS];		/* expiretime for block-quota */
-	char rsquash[MAXQUOTAS];		/* for quotas threath root as any other user */
+	char rsquash[MAXQUOTAS];		/* for quotas treat root as any other user */
 };
 
 struct vfsmount
diff -u --recursive --new-file v2.3.9/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.9/linux/include/linux/parport.h	Tue Jun 22 14:42:44 1999
+++ linux/include/linux/parport.h	Wed Jul  7 09:21:33 1999
@@ -20,8 +20,6 @@
 #define PARPORT_CONTROL_AUTOFD    0x2
 #define PARPORT_CONTROL_INIT      0x4
 #define PARPORT_CONTROL_SELECT    0x8
-#define PARPORT_CONTROL_INTEN     0x10
-#define PARPORT_CONTROL_DIRECTION 0x20
 
 #define PARPORT_STATUS_ERROR      0x8
 #define PARPORT_STATUS_SELECT     0x10
@@ -43,28 +41,43 @@
 	PARPORT_CLASS_SCANNER,
 	PARPORT_CLASS_DIGCAM,
 	PARPORT_CLASS_OTHER,            /* Anything else */
-	PARPORT_CLASS_UNSPEC            /* No CLS field in ID */
+	PARPORT_CLASS_UNSPEC,           /* No CLS field in ID */
+	PARPORT_CLASS_SCSIADAPTER
 } parport_device_class;
 
-/* The "modes" entry in parport is a bit field representing the following
- * modes.
- * Note that PARPORT_MODE_PCECPEPP is for the SMC EPP+ECP mode which is NOT
- * 100% compatible with EPP.
- */
-#define PARPORT_MODE_PCSPP	        0x0001
-#define PARPORT_MODE_PCPS2		0x0002
-#define PARPORT_MODE_PCEPP		0x0004
-#define PARPORT_MODE_PCECP		0x0008
-#define PARPORT_MODE_PCECPEPP		0x0010
-#define PARPORT_MODE_PCECR		0x0020  /* ECR Register Exists */
-#define PARPORT_MODE_PCECPPS2		0x0040
+/* The "modes" entry in parport is a bit field representing the
+   capabilities of the hardware. */
+#define PARPORT_MODE_PCSPP	(1<<0) /* IBM PC registers available. */
+#define PARPORT_MODE_TRISTATE	(1<<1) /* Can tristate. */
+#define PARPORT_MODE_EPP	(1<<2) /* Hardware EPP. */
+#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. */
+
+/* IEEE1284 modes: 
+   Nibble mode, byte mode, ECP, ECPRLE and EPP are their own
+   'extensibility request' values.  Others are special.
+   'Real' ECP modes must have the IEEE1284_MODE_ECP bit set.  */
+#define IEEE1284_MODE_NIBBLE             0
+#define IEEE1284_MODE_BYTE              (1<<0)
+#define IEEE1284_MODE_COMPAT            (1<<8)
+#define IEEE1284_MODE_BECP              (1<<9) /* Bounded ECP mode */
+#define IEEE1284_MODE_ECP               (1<<4)
+#define IEEE1284_MODE_ECPRLE            (IEEE1284_MODE_ECP | (1<<5))
+#define IEEE1284_MODE_ECPSWE            (1<<10) /* Software-emulated */
+#define IEEE1284_MODE_EPP               (1<<6)
+#define IEEE1284_MODE_EPPSL             (1<<11) /* EPP 1.7 */
+#define IEEE1284_MODE_EPPSWE            (1<<12) /* Software-emulated */
+#define IEEE1284_DEVICEID               (1<<2)  /* This is a flag */
 
 /* The rest is for the kernel only */
 #ifdef __KERNEL__
 
+#include <linux/wait.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/spinlock.h>
+#include <asm/semaphore.h>
 #include <linux/proc_fs.h>
 #include <linux/config.h>
 
@@ -72,59 +85,92 @@
 
 /* Define this later. */
 struct parport;
+struct pardevice;
 
 struct pc_parport_state {
 	unsigned int ctr;
 	unsigned int ecr;
 };
 
+struct ax_parport_state {
+	unsigned int ctr;
+	unsigned int ecr;
+	unsigned int dcsr;
+};
+
+/* used by both parport_amiga and parport_mfc3 */
+struct amiga_parport_state {
+       unsigned char data;     /* ciaa.prb */
+       unsigned char datadir;  /* ciaa.ddrb */
+       unsigned char status;   /* ciab.pra & 7 */
+       unsigned char statusdir;/* ciab.ddrb & 7 */
+};
+
 struct parport_state {
 	union {
 		struct pc_parport_state pc;
 		/* ARC has no state. */
-		/* AX uses same state information as PC */
+		struct ax_parport_state ax;
+		struct amiga_parport_state amiga;
+		/* Atari has not state. */
 		void *misc; 
 	} u;
 };
 
 struct parport_operations {
+	/* IBM PC-style virtual registers. */
 	void (*write_data)(struct parport *, unsigned char);
 	unsigned char (*read_data)(struct parport *);
+
 	void (*write_control)(struct parport *, unsigned char);
 	unsigned char (*read_control)(struct parport *);
-	unsigned char (*frob_control)(struct parport *, unsigned char mask, unsigned char val);
-	void (*write_econtrol)(struct parport *, unsigned char);
-	unsigned char (*read_econtrol)(struct parport *);
-	unsigned char (*frob_econtrol)(struct parport *, unsigned char mask, unsigned char val);
-	void (*write_status)(struct parport *, unsigned char);
+	unsigned char (*frob_control)(struct parport *, unsigned char mask,
+				      unsigned char val);
+
 	unsigned char (*read_status)(struct parport *);
-	void (*write_fifo)(struct parport *, unsigned char);
-	unsigned char (*read_fifo)(struct parport *);
 
-	void (*change_mode)(struct parport *, int);
+	/* IRQs. */
+	void (*enable_irq)(struct parport *);
+	void (*disable_irq)(struct parport *);
 
-	void (*epp_write_data)(struct parport *, unsigned char);
-	unsigned char (*epp_read_data)(struct parport *);
-	void (*epp_write_addr)(struct parport *, unsigned char);
-	unsigned char (*epp_read_addr)(struct parport *);
-	int (*epp_check_timeout)(struct parport *);
-	size_t (*epp_write_block)(struct parport *, void *, size_t);
-	size_t (*epp_read_block)(struct parport *, void *, size_t);
+	/* Data direction. */
+	void (*data_forward) (struct parport *);
+	void (*data_reverse) (struct parport *);
 
-	int (*ecp_write_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
-	int (*ecp_read_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
+	/* For core parport code. */
+	void (*interrupt)(int, void *, struct pt_regs *); /* ? */
 
-	void (*init_state)(struct parport_state *);
+	void (*init_state)(struct pardevice *, struct parport_state *);
 	void (*save_state)(struct parport *, struct parport_state *);
 	void (*restore_state)(struct parport *, struct parport_state *);
 
-	void (*enable_irq)(struct parport *);
-	void (*disable_irq)(struct parport *);
-	void (*interrupt)(int, void *, struct pt_regs *);
-
 	void (*inc_use_count)(void);
 	void (*dec_use_count)(void);
-	void (*fill_inode)(struct inode *inode, int fill);
+	void (*fill_inode)(struct inode *inode, int fill); /* ? */
+
+	/* Block read/write */
+	size_t (*epp_write_data) (struct parport *port, const void *buf,
+				  size_t len, int flags);
+	size_t (*epp_read_data) (struct parport *port, void *buf, size_t len,
+				 int flags);
+	size_t (*epp_write_addr) (struct parport *port, const void *buf,
+				  size_t len, int flags);
+	size_t (*epp_read_addr) (struct parport *port, void *buf, size_t len,
+				 int flags);
+
+	size_t (*ecp_write_data) (struct parport *port, const void *buf,
+				  size_t len, int flags);
+	size_t (*ecp_read_data) (struct parport *port, void *buf, size_t len,
+				 int flags);
+	size_t (*ecp_write_addr) (struct parport *port, const void *buf,
+				  size_t len, int flags);
+
+	size_t (*compat_write_data) (struct parport *port, const void *buf,
+				     size_t len, int flags);
+	size_t (*nibble_read_data) (struct parport *port, void *buf,
+				    size_t len, int flags);
+	size_t (*byte_read_data) (struct parport *port, void *buf,
+				  size_t len, int flags);
 };
 
 struct parport_device_info {
@@ -152,6 +198,7 @@
 struct pardevice {
 	const char *name;
 	struct parport *port;
+	int daisy;
 	int (*preempt)(void *);
 	void (*wakeup)(void *);
 	void *private;
@@ -163,34 +210,66 @@
 	wait_queue_head_t wait_q;
 	unsigned long int time;
 	unsigned long int timeslice;
+	volatile long int timeout;
 	unsigned int waiting;
 	struct pardevice *waitprev;
 	struct pardevice *waitnext;
-        void * sysctl_table;
+	void * sysctl_table;
 };
 
-/* Directory information for the /proc interface */
-struct parport_dir {
-	struct proc_dir_entry *entry;    /* Directory /proc/parport/X     */
-	struct proc_dir_entry *irq;	/*		.../irq           */
-	struct proc_dir_entry *devices;  /*		.../devices       */
-	struct proc_dir_entry *hardware; /*		.../hardware      */
-	struct proc_dir_entry *probe;	 /*		.../autoprobe	  */
-	char name[4];
+/* IEEE1284 information */
+
+/* IEEE1284 phases */
+enum ieee1284_phase {
+	IEEE1284_PH_FWD_DATA,
+	IEEE1284_PH_FWD_IDLE,
+	IEEE1284_PH_TERMINATE,
+	IEEE1284_PH_NEGOTIATION,
+	IEEE1284_PH_HBUSY_DNA,
+	IEEE1284_PH_REV_IDLE,
+	IEEE1284_PH_HBUSY_DAVAIL,
+	IEEE1284_PH_REV_DATA,
+	IEEE1284_PH_ECP_SETUP,
+	IEEE1284_PH_ECP_FWD_TO_REV,
+	IEEE1284_PH_ECP_REV_TO_FWD
+};
+struct ieee1284_info {
+	int mode;
+	volatile enum ieee1284_phase phase;
+	struct semaphore irq;
 };
 
 /* A parallel port */
 struct parport {
 	unsigned long base;	/* base address */
-	unsigned long base_hi;	/* base address (ECR) */
+	unsigned long base_hi;  /* base address (hi - ECR) */
 	unsigned int size;	/* IO extent */
 	const char *name;
+	unsigned int modes;
 	int irq;		/* interrupt (or -1 for none) */
 	int dma;
-	unsigned int modes;
+	int muxport;		/* which muxport (if any) this is */
+	int portnum;		/* which physical parallel port (not mux) */
+
+	struct parport *physport;
+				/* If this is a non-default mux
+				   parport, i.e. we're a clone of a real
+				   physical port, this is a pointer to that
+				   port. The locking is only done in the
+				   real port.  For a clone port, the
+				   following structure members are
+				   meaningless: devices, cad, muxsel,
+				   waithead, waittail, flags, pdir,
+				   ieee1284, *_lock.
+
+				   It this is a default mux parport, or
+				   there is no mux involved, this points to
+				   ourself. */
 
 	struct pardevice *devices;
 	struct pardevice *cad;	/* port owner */
+	int daisy;		/* currently selected daisy addr */
+	int muxsel;		/* currently selected mux port */
 
 	struct pardevice *waithead;
 	struct pardevice *waittail;
@@ -198,8 +277,9 @@
 	struct parport *next;
 	unsigned int flags;
 
-	struct parport_dir pdir;
-	struct parport_device_info probe_info; 
+	void *sysctl_table;
+	struct parport_device_info probe_info[5]; /* 0-3 + non-IEEE1284.3 */
+	struct ieee1284_info ieee1284;
 
 	struct parport_operations *ops;
 	void *private_data;     /* for lowlevel driver */
@@ -208,9 +288,12 @@
 	spinlock_t pardevice_lock;
 	spinlock_t waitlist_lock;
 	rwlock_t cad_lock;
-        void * sysctl_table;
+
+	int spintime;
 };
 
+#define DEFAULT_SPIN_TIME 500 /* us */
+
 struct parport_driver {
 	const char *name;
 	void (*attach) (struct parport *);
@@ -218,11 +301,10 @@
 	struct parport_driver *next;
 };
 
-/* parport_register_port registers a new parallel port at the given address (if
- * one does not already exist) and returns a pointer to it.  This entails
- * claiming the I/O region, IRQ and DMA.
- * NULL is returned if initialisation fails. 
- */
+/* parport_register_port registers a new parallel port at the given
+   address (if one does not already exist) and returns a pointer to it.
+   This entails claiming the I/O region, IRQ and DMA.  NULL is returned
+   if initialisation fails. */
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
 				      struct parport_operations *ops);
 
@@ -236,12 +318,12 @@
 /* Unregister a port. */
 extern void parport_unregister_port(struct parport *port);
 
-/* parport_in_use returns nonzero if there are devices attached to a port. */
+/* parport_in_use returns nonzero if there are devices attached to a
+   port. */
 #define parport_in_use(x)  ((x)->devices != NULL)
 
-/* parport_enumerate returns a pointer to the linked list of all the ports
- * in this machine.
- */
+/* parport_enumerate returns a pointer to the linked list of all the
+   ports in this machine. */
 struct parport *parport_enumerate(void);
 
 /* Register a new high-level driver. */
@@ -250,13 +332,12 @@
 /* Unregister a high-level driver. */
 extern void parport_unregister_driver (struct parport_driver *);
 
-/* parport_register_device declares that a device is connected to a port, and 
- * tells the kernel all it needs to know.  
- * pf is the preemption function (may be NULL for no callback)
- * kf is the wake-up function (may be NULL for no callback)
- * irq_func is the interrupt handler (may be NULL for no interrupts)
- * handle is a user pointer that gets handed to callback functions. 
- */
+/* parport_register_device declares that a device is connected to a
+   port, and tells the kernel all it needs to know.  pf is the
+   preemption function (may be NULL for no callback) kf is the wake-up
+   function (may be NULL for no callback) irq_func is the interrupt
+   handler (may be NULL for no interrupts) handle is a user pointer
+   that gets handed to callback functions.  */
 struct pardevice *parport_register_device(struct parport *port, 
 			  const char *name,
 			  int (*pf)(void *), void (*kf)(void *),
@@ -266,30 +347,29 @@
 /* parport_unregister unlinks a device from the chain. */
 extern void parport_unregister_device(struct pardevice *dev);
 
-/* parport_claim tries to gain ownership of the port for a particular driver.
- * This may fail (return non-zero) if another driver is busy.  If this
- * driver has registered an interrupt handler, it will be enabled. 
- */
+/* parport_claim tries to gain ownership of the port for a particular
+   driver.  This may fail (return non-zero) if another driver is busy.
+   If this driver has registered an interrupt handler, it will be
+   enabled.  */
 extern int parport_claim(struct pardevice *dev);
 
-/* parport_claim_or_block is the same, but sleeps if the port cannot be 
-   claimed.  Return value is 1 if it slept, 0 normally and -errno on error.  */
+/* parport_claim_or_block is the same, but sleeps if the port cannot
+   be claimed.  Return value is 1 if it slept, 0 normally and -errno
+   on error.  */
 extern int parport_claim_or_block(struct pardevice *dev);
 
-/* parport_release reverses a previous parport_claim.  This can never fail, 
- * though the effects are undefined (except that they are bad) if you didn't
- * previously own the port.  Once you have released the port you should make
- * sure that neither your code nor the hardware on the port tries to initiate
- * any communication without first re-claiming the port.
- * If you mess with the port state (enabling ECP for example) you should
- * clean up before releasing the port. 
- */
+/* parport_release reverses a previous parport_claim.  This can never
+   fail, though the effects are undefined (except that they are bad)
+   if you didn't previously own the port.  Once you have released the
+   port you should make sure that neither your code nor the hardware
+   on the port tries to initiate any communication without first
+   re-claiming the port.  If you mess with the port state (enabling
+   ECP for example) you should clean up before releasing the port. */
 
 extern void parport_release(struct pardevice *dev);
 
 /* parport_yield relinquishes the port if it would be helpful to other
- * drivers.  The return value is the same as for parport_claim.
- */
+   drivers.  The return value is the same as for parport_claim.  */
 extern __inline__ int parport_yield(struct pardevice *dev)
 {
 	unsigned long int timeslip = (jiffies - dev->time);
@@ -300,8 +380,7 @@
 }
 
 /* parport_yield_blocking is the same but uses parport_claim_or_block
- * instead of parport_claim.
- */
+   instead of parport_claim.  */
 extern __inline__ int parport_yield_blocking(struct pardevice *dev)
 {
 	unsigned long int timeslip = (jiffies - dev->time);
@@ -311,37 +390,87 @@
 	return parport_claim_or_block(dev);
 }
 
-/*
- * Lowlevel drivers _can_ call this support function to handle irqs.
- */
-extern __inline__ void parport_generic_irq(int irq, struct parport *port,
-					   struct pt_regs *regs)
-{
-	read_lock(&port->cad_lock);
-	if (!port->cad)
-		goto out_unlock;
-	if (port->cad->irq_func)
-		port->cad->irq_func(irq, port->cad->private, regs);
-	else
-		printk(KERN_ERR "%s: irq%d happened with irq_func NULL "
-		       "with %s as cad!\n", port->name, irq, port->cad->name);
- out_unlock:
-	read_unlock(&port->cad_lock);
-}
-
 /* Flags used to identify what a device does. */
 #define PARPORT_DEV_TRAN		0	/* WARNING !! DEPRECATED !! */
 #define PARPORT_DEV_LURK		(1<<0)	/* WARNING !! DEPRECATED !! */
 #define PARPORT_DEV_EXCL		(1<<1)	/* Need exclusive access. */
 
-#define PARPORT_FLAG_COMA_		(1<<0)  /* No longer used. */
 #define PARPORT_FLAG_EXCL		(1<<1)	/* EXCL driver registered. */
 
 extern int parport_parse_irqs(int, const char *[], int irqval[]);
-extern int parport_parse_dmas(int, const char *[], int irqval[]);
-extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
-extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
-				   char);
+extern int parport_parse_dmas(int, const char *[], int dmaval[]);
+
+/* IEEE1284 functions */
+extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
+extern int parport_negotiate (struct parport *, int mode);
+extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
+extern ssize_t parport_read (struct parport *, void *buf, size_t len);
+extern long parport_set_timeout (struct pardevice *, long inactivity);
+extern int parport_wait_event (struct parport *, long timeout);
+extern int parport_wait_peripheral (struct parport *port,
+				    unsigned char mask,
+				    unsigned char val);
+
+/* For architectural drivers */
+extern void parport_ieee1284_wakeup (struct parport *port);
+extern size_t parport_ieee1284_write_compat (struct parport *,
+					     const void *, size_t, int);
+extern size_t parport_ieee1284_read_nibble (struct parport *,
+					    void *, size_t, int);
+extern size_t parport_ieee1284_read_byte (struct parport *,
+					  void *, size_t, int);
+extern size_t parport_ieee1284_ecp_read_data (struct parport *,
+					      void *, size_t, int);
+extern size_t parport_ieee1284_ecp_write_data (struct parport *,
+					       const void *, size_t, int);
+extern size_t parport_ieee1284_ecp_write_addr (struct parport *,
+					       const void *, size_t, int);
+extern size_t parport_ieee1284_epp_write_data (struct parport *,
+					       const void *, size_t, int);
+extern size_t parport_ieee1284_epp_read_data (struct parport *,
+					      void *, size_t, int);
+extern size_t parport_ieee1284_epp_write_addr (struct parport *,
+					       const void *, size_t, int);
+extern size_t parport_ieee1284_epp_read_addr (struct parport *,
+					      void *, size_t, int);
+
+/* IEEE1284.3 functions */
+extern int parport_daisy_init (struct parport *port);
+extern void parport_daisy_fini (struct parport *port);
+extern struct pardevice *parport_open (int devnum, const char *name,
+				       int (*pf) (void *),
+				       void (*kf) (void *),
+				       void (*irqf) (int, void *,
+						     struct pt_regs *),
+				       int flags, void *handle);
+extern void parport_close (struct pardevice *dev);
+extern ssize_t parport_device_id (int devnum, char *buffer, size_t len);
+extern int parport_device_num (int parport, int mux, int daisy);
+extern int parport_device_coords (int devnum, int *parport, int *mux,
+				  int *daisy);
+extern void parport_daisy_deselect_all (struct parport *port);
+extern int parport_daisy_select (struct parport *port, int daisy, int mode);
+
+/* For finding devices based on their device ID.  Example usage:
+   int devnum = -1;
+   while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) {
+       struct pardevice *dev = parport_open (devnum, ...);
+       ...
+   }
+*/
+extern int parport_find_device (const char *mfg, const char *mdl, int from);
+extern int parport_find_class (parport_device_class cls, int from);
+
+/* Lowlevel drivers _can_ call this support function to handle irqs.  */
+extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+					   struct pt_regs *regs)
+{
+	parport_ieee1284_interrupt (irq, port, regs);
+	read_lock(&port->cad_lock);
+	if (port->cad && port->cad->irq_func)
+		port->cad->irq_func(irq, port->cad->private, regs);
+	read_unlock(&port->cad_lock);
+}
 
 /* Prototypes from parport_procfs */
 extern int parport_proc_register(struct parport *pp);
@@ -354,12 +483,8 @@
 extern void dec_parport_count(void);
 extern void inc_parport_count(void);
 
-extern int parport_probe(struct parport *port, char *buffer, int len);
-extern void parport_probe_one(struct parport *port);
-extern void (*parport_probe_hook)(struct parport *port);
-
 /* 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_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)
 #undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
 #define parport_write_data(p,x)            parport_pc_write_data(p,x)
@@ -367,21 +492,11 @@
 #define parport_write_control(p,x)         parport_pc_write_control(p,x)
 #define parport_read_control(p)            parport_pc_read_control(p)
 #define parport_frob_control(p,m,v)        parport_pc_frob_control(p,m,v)
-#define parport_write_econtrol(p,x)        parport_pc_write_econtrol(p,x)
-#define parport_read_econtrol(p)           parport_pc_read_econtrol(p)
-#define parport_frob_econtrol(p,m,v)       parport_pc_frob_econtrol(p,m,v)
-#define parport_write_status(p,v)          parport_pc_write_status(p,v)
 #define parport_read_status(p)             parport_pc_read_status(p)
-#define parport_write_fifo(p,v)            parport_pc_write_fifo(p,v)
-#define parport_read_fifo(p)               parport_pc_read_fifo(p)
-#define parport_change_mode(p,m)           parport_pc_change_mode(p,m)
-#define parport_release_resources(p)       parport_pc_release_resources(p)
-#define parport_claim_resources(p)         parport_pc_claim_resources(p)
-#define parport_epp_write_data(p,x)        parport_pc_write_epp(p,x)
-#define parport_epp_read_data(p)           parport_pc_read_epp(p)
-#define parport_epp_write_addr(p,x)        parport_pc_write_epp_addr(p,x)
-#define parport_epp_read_addr(p)           parport_pc_read_epp_addr(p)
-#define parport_epp_check_timeout(p)       parport_pc_check_epp_timeout(p)
+#define parport_enable_irq(p)              parport_pc_enable_irq(p)
+#define parport_disable_irq(p)             parport_pc_disable_irq(p)
+#define parport_data_forward(p)            parport_pc_data_forward(p)
+#define parport_data_reverse(p)            parport_pc_data_reverse(p)
 #endif
 
 #ifdef PARPORT_NEED_GENERIC_OPS
@@ -391,21 +506,11 @@
 #define parport_write_control(p,x)         (p)->ops->write_control(p,x)
 #define parport_read_control(p)            (p)->ops->read_control(p)
 #define parport_frob_control(p,m,v)        (p)->ops->frob_control(p,m,v)
-#define parport_write_econtrol(p,x)        (p)->ops->write_econtrol(p,x)
-#define parport_read_econtrol(p)           (p)->ops->read_econtrol(p)
-#define parport_frob_econtrol(p,m,v)       (p)->ops->frob_econtrol(p,m,v)
-#define parport_write_status(p,v)          (p)->ops->write_status(p,v)
 #define parport_read_status(p)             (p)->ops->read_status(p)
-#define parport_write_fifo(p,v)            (p)->ops->write_fifo(p,v)
-#define parport_read_fifo(p)               (p)->ops->read_fifo(p)
-#define parport_change_mode(p,m)           (p)->ops->change_mode(p,m)
-#define parport_release_resources(p)       (p)->ops->release_resources(p)
-#define parport_claim_resources(p)         (p)->ops->claim_resources(p)
-#define parport_epp_write_data(p,x)        (p)->ops->epp_write_data(p,x)
-#define parport_epp_read_data(p)           (p)->ops->epp_read_data(p)
-#define parport_epp_write_addr(p,x)        (p)->ops->epp_write_addr(p,x)
-#define parport_epp_read_addr(p)           (p)->ops->epp_read_addr(p)
-#define parport_epp_check_timeout(p)       (p)->ops->epp_check_timeout(p)
+#define parport_enable_irq(p)              (p)->ops->enable_irq(p)
+#define parport_disable_irq(p)             (p)->ops->disable_irq(p)
+#define parport_data_forward(p)            (p)->ops->data_forward(p)
+#define parport_data_reverse(p)            (p)->ops->data_reverse(p)
 #endif
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.3.9/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.3.9/linux/include/linux/parport_pc.h	Tue Jun 22 14:41:46 1999
+++ linux/include/linux/parport_pc.h	Wed Jul  7 09:20:54 1999
@@ -5,57 +5,39 @@
 
 /* --- register definitions ------------------------------- */
 
-#define ECONTROL(p)	((p)->base_hi + 0x02)
-#define CONFIGB(p)	((p)->base_hi + 0x01)
-#define CONFIGA(p)	((p)->base_hi + 0x00)
-#define EPPDATA(p)	((p)->base    + 0x04)
-#define EPPADDR(p)	((p)->base    + 0x03)
-#define CONTROL(p)	((p)->base    + 0x02)
-#define STATUS(p)	((p)->base    + 0x01)
-#define DATA(p)		((p)->base    + 0x00)
+#define ECONTROL(p) ((p)->base_hi + 0x2)
+#define CONFIGB(p)  ((p)->base_hi + 0x1)
+#define CONFIGA(p)  ((p)->base_hi + 0x0)
+#define FIFO(p)     ((p)->base_hi + 0x0)
+#define EPPDATA(p)  ((p)->base    + 0x4)
+#define EPPADDR(p)  ((p)->base    + 0x3)
+#define CONTROL(p)  ((p)->base    + 0x2)
+#define STATUS(p)   ((p)->base    + 0x1)
+#define DATA(p)     ((p)->base    + 0x0)
 
-/* Private data for PC low-level driver. */
 struct parport_pc_private {
 	/* Contents of CTR. */
 	unsigned char ctr;
-};
 
-extern int parport_pc_epp_clear_timeout(struct parport *pb);
+	/* Bitmask of writable CTR bits. */
+	unsigned char ctr_writable;
 
-extern volatile unsigned char parport_pc_ctr;
+	/* Whether or not there's an ECR. */
+	int ecr;
 
-extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
-{
-	outb(d, EPPDATA(p));
-}
-
-extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
-{
-	return inb(EPPDATA(p));
-}
+	/* Number of PWords that FIFO will hold. */
+	int fifo_depth;
 
-extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
-{
-	outb(d, EPPADDR(p));
-}
+	/* Number of bytes per portword. */
+	int pword;
 
-extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
-{
-	return inb(EPPADDR(p));
-}
+	/* Not used yet. */
+	int readIntrThreshold;
+	int writeIntrThreshold;
 
-extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
-{
-	if (!(inb(STATUS(p)) & 1))
-		return 0;
-	parport_pc_epp_clear_timeout(p);
-	return 1;
-}
-
-extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
-{
-	return inb(CONFIGB(p));
-}
+	/* buffer suitable for DMA, if DMA enabled */
+	char *dma_buf;
+};
 
 extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
@@ -67,31 +49,68 @@
 	return inb(DATA(p));
 }
 
-extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
+extern __inline__ unsigned char __frob_control (struct parport *p,
+						unsigned char mask,
+						unsigned char val)
 {
-	struct parport_pc_private *priv = p->private_data;
-	priv->ctr = d;/* update soft copy */
-	outb(d, CONTROL(p));
+	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 */
 }
 
-extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
+extern __inline__ void parport_pc_data_reverse (struct parport *p)
 {
-	struct parport_pc_private *priv = p->private_data;
-	return priv->ctr;
+	__frob_control (p, 0x20, 0x20);
 }
 
-extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
+extern __inline__ void parport_pc_write_control (struct parport *p,
+						 unsigned char d)
 {
-	struct parport_pc_private *priv = p->private_data;
-	unsigned char ctr = priv->ctr;
-	ctr = (ctr & ~mask) ^ val;
-	outb (ctr, CONTROL(p));
-	return priv->ctr = ctr; /* update soft copy */
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to newer interface. */
+	if (d & 0x20) {
+			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+					p->name, p->cad->name);
+			parport_pc_data_reverse (p);
+	}
+
+	__frob_control (p, wm, d & wm);
 }
 
-extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
+extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
 {
-	outb(d, STATUS(p));
+	const struct parport_pc_private *priv = p->physport->private_data;
+	return priv->ctr; /* Use soft copy */
+}
+
+extern __inline__ unsigned char parport_pc_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);
+
+	/* Take this out when drivers have adapted to newer interface. */
+	if (mask & 0x20) {
+			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+					p->name, p->cad->name);
+			parport_pc_data_reverse (p);
+	}
+
+	/* Restrict mask and val to control lines. */
+	mask &= wm;
+	val &= wm;
+
+	return __frob_control (p, mask, val);
 }
 
 extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
@@ -99,50 +118,30 @@
 	return inb(STATUS(p));
 }
 
-extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d)
+extern __inline__ void parport_pc_data_forward (struct parport *p)
 {
-	outb(d, ECONTROL(p));
+	__frob_control (p, 0x20, 0x00);
 }
 
-extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p)
+extern __inline__ void parport_pc_disable_irq(struct parport *p)
 {
-	return inb(ECONTROL(p));
+	__frob_control (p, 0x10, 0x00);
 }
 
-extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
+extern __inline__ void parport_pc_enable_irq(struct parport *p)
 {
-	unsigned char old = inb(ECONTROL(p));
-	outb(((old & ~mask) ^ val), ECONTROL(p));
-	return old;
+	__frob_control (p, 0x10, 0x10);
 }
 
-extern void parport_pc_change_mode(struct parport *p, int m);
-
-extern void parport_pc_write_fifo(struct parport *p, unsigned char v);
-
-extern unsigned char parport_pc_read_fifo(struct parport *p);
-
-extern void parport_pc_disable_irq(struct parport *p);
-
-extern void parport_pc_enable_irq(struct parport *p);
-
 extern void parport_pc_release_resources(struct parport *p);
 
 extern int parport_pc_claim_resources(struct parport *p);
 
-extern void parport_pc_init_state(struct parport_state *s);
+extern void parport_pc_init_state(struct pardevice *, struct parport_state *s);
 
 extern void parport_pc_save_state(struct parport *p, struct parport_state *s);
 
 extern void parport_pc_restore_state(struct parport *p, struct parport_state *s);
-
-extern size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length);
-
-extern size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length);
-
-extern int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
-
-extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
 
 extern void parport_pc_inc_use_count(void);
 
diff -u --recursive --new-file v2.3.9/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.9/linux/include/linux/pci.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/pci.h	Thu Jul  8 14:50:20 1999
@@ -273,6 +273,9 @@
 #define PCI_CLASS_SERIAL_USB		0x0c03
 #define PCI_CLASS_SERIAL_FIBER		0x0c04
 
+#define PCI_BASE_CLASS_INTELLIGENT	0x0e
+#define PCI_CLASS_INTELLIGENT_I2O	0x0e00
+
 #define PCI_CLASS_HOT_SWAP_CONTROLLER	0xff00
 
 #define PCI_CLASS_OTHERS		0xff
@@ -305,6 +308,7 @@
 #define PCI_DEVICE_ID_NCR_53C895	0x000c
 #define PCI_DEVICE_ID_NCR_53C885	0x000d
 #define PCI_DEVICE_ID_NCR_53C875	0x000f
+#define PCI_DEVICE_ID_NCR_53C1510	0x0010
 #define PCI_DEVICE_ID_NCR_53C875J	0x008f
 
 #define PCI_VENDOR_ID_ATI		0x1002
@@ -368,6 +372,7 @@
 #define PCI_DEVICE_ID_DEC_21152		0x0024
 #define PCI_DEVICE_ID_DEC_21153		0x0025
 #define PCI_DEVICE_ID_DEC_21154		0x0026
+#define PCI_DEVICE_ID_COMPAQ_42XX	0x0046
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
 #define PCI_DEVICE_ID_CIRRUS_7548	0x0038
@@ -403,6 +408,7 @@
 
 #define PCI_VENDOR_ID_AMD		0x1022
 #define PCI_DEVICE_ID_AMD_LANCE		0x2000
+#define PCI_DEVICE_ID_AMD_LANCE_HOME	0x2001
 #define PCI_DEVICE_ID_AMD_SCSI		0x2020
 
 #define PCI_VENDOR_ID_TRIDENT		0x1023
@@ -616,6 +622,9 @@
 #define PCI_VENDOR_ID_SIERRA		0x10a8
 #define PCI_DEVICE_ID_SIERRA_STB	0x0000
 
+#define PCI_VENDOR_ID_SGI		0x10a9
+#define PCI_DEVICE_ID_SGI_IOC3		0x0003
+
 #define PCI_VENDOR_ID_ACC		0x10aa
 #define PCI_DEVICE_ID_ACC_2056		0x0000
 
@@ -686,6 +695,8 @@
 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002
 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003
 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV       0x0005
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS   0x0083
 
 #define PCI_VENDOR_ID_ASP		0x10cd
 #define PCI_DEVICE_ID_ASP_ABP940	0x1200
@@ -868,6 +879,9 @@
 #define PCI_VENDOR_ID_GALILEO		0x11ab
 #define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
 
+#define PCI_VENDOR_ID_GALILEO		0x11ab
+#define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
+
 #define PCI_VENDOR_ID_LITEON		0x11ad
 #define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
 
@@ -966,6 +980,7 @@
 
 #define PCI_VENDOR_ID_ENSONIQ		0x1274
 #define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI	0x5000
+#define PCI_DEVICE_ID_ENSONIQ_ES1371    0x1371
 
 #define PCI_VENDOR_ID_ALTEON		0x12ae
 #define PCI_DEVICE_ID_ALTEON_ACENIC	0x0001
@@ -1032,6 +1047,7 @@
 #define PCI_DEVICE_ID_GENROCO_HFP832	0x0003
 
 #define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_DEVICE_ID_INTEL_21145	0x0039
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
 #define PCI_DEVICE_ID_INTEL_82424	0x0483
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
@@ -1075,6 +1091,7 @@
 #define PCI_VENDOR_ID_ADAPTEC		0x9004
 #define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
 #define PCI_DEVICE_ID_ADAPTEC_7821	0x2178
+#define PCI_DEVICE_ID_ADAPTEC_38602	0x3860
 #define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
 #define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
diff -u --recursive --new-file v2.3.9/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.9/linux/include/linux/proc_fs.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/proc_fs.h	Wed Jul  7 09:21:05 1999
@@ -375,6 +375,7 @@
     }
 }
 
+extern struct super_block *proc_super_blocks;
 extern struct dentry_operations proc_dentry_operations;
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
 extern int init_proc_fs(void);
@@ -456,12 +457,12 @@
 
 #else
 
-extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) {};
-extern inline int proc_unregister(struct proc_dir_entry *a, int b) {};
-extern inline int proc_net_register(struct proc_dir_entry *a) {};
-extern inline int proc_net_unregister(int x) {};
-extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) {};
-extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x);
+extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) { return 0; }
+extern inline int proc_unregister(struct proc_dir_entry *a, int b) { return 0; }
+extern inline int proc_net_register(struct proc_dir_entry *a) { return 0; }
+extern inline int proc_net_unregister(int x) { return 0; }
+extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) { return 0; }
+extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x) { return 0; }
 
 extern inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
 					 struct proc_dir_entry *parent)
diff -u --recursive --new-file v2.3.9/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.9/linux/include/linux/sched.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/sched.h	Wed Jul  7 09:20:45 1999
@@ -172,6 +172,7 @@
 	atomic_t count;
 	int map_count;				/* number of VMAs */
 	struct semaphore mmap_sem;
+	spinlock_t page_table_lock;
 	unsigned long context;
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
@@ -193,6 +194,7 @@
 		swapper_pg_dir, 			\
 		ATOMIC_INIT(1), 1,			\
 		__MUTEX_INITIALIZER(name.mmap_sem),	\
+		SPIN_LOCK_UNLOCKED,			\
 		0,					\
 		0, 0, 0, 0,				\
 		0, 0, 0, 				\
@@ -343,7 +345,7 @@
  */
 #define _STK_LIM	(8*1024*1024)
 
-#define DEF_PRIORITY	(20*HZ/100)	/* 210 ms time slices */
+#define DEF_PRIORITY	(20*HZ/100)	/* 200 ms time slices */
 
 /*
  *  INIT_TASK is used to set up the first task table, touch at
diff -u --recursive --new-file v2.3.9/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v2.3.9/linux/include/linux/soundcard.h	Sat Oct 24 11:40:16 1998
+++ linux/include/linux/soundcard.h	Mon Jul  5 20:02:10 1999
@@ -891,6 +891,12 @@
 #define SOUND_MIXER_ACCESS		_SIOWR('M', 102, mixer_record)
 
 /*
+ * Two ioctls for special souncard function
+ */
+#define SOUND_MIXER_AGC  _SIOWR('M', 103, int)
+#define SOUND_MIXER_3DSE  _SIOWR('M', 104, int)
+
+/*
  * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers.
  * These features can be used when accessing device specific features.
  */
diff -u --recursive --new-file v2.3.9/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.9/linux/include/linux/swap.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/swap.h	Wed Jul  7 09:20:38 1999
@@ -90,9 +90,6 @@
 extern void swap_after_unlock_page (unsigned long entry);
 
 /* linux/mm/page_alloc.c */
-extern void swap_in(struct task_struct *, struct vm_area_struct *,
-		    pte_t *, unsigned long, int);
-
 
 /* linux/mm/swap_state.c */
 extern void show_swap_cache_info(void);
diff -u --recursive --new-file v2.3.9/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.3.9/linux/include/linux/tty.h	Tue Jun 22 14:41:46 1999
+++ linux/include/linux/tty.h	Wed Jul  7 09:20:44 1999
@@ -277,6 +277,7 @@
 	struct tq_struct tq_hangup;
 	void *disc_data;
 	void *driver_data;
+	struct list_head tty_files;
 
 #define N_TTY_BUF_SIZE 4096
 	
diff -u --recursive --new-file v2.3.9/linux/include/linux/video_decoder.h linux/include/linux/video_decoder.h
--- v2.3.9/linux/include/linux/video_decoder.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/video_decoder.h	Mon Jul  5 20:02:10 1999
@@ -0,0 +1,37 @@
+#ifndef _LINUX_VIDEO_DECODER_H
+#define _LINUX_VIDEO_DECODER_H
+
+struct video_decoder_capability { /* this name is too long */
+	__u32	flags;
+#define	VIDEO_DECODER_PAL	1	/* can decode PAL signal */
+#define	VIDEO_DECODER_NTSC	2	/* can decode NTSC */
+#define	VIDEO_DECODER_SECAM	4	/* can decode SECAM */
+#define	VIDEO_DECODER_AUTO	8	/* can autosense norm */
+#define	VIDEO_DECODER_CCIR	16	/* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+	int	inputs;			/* number of inputs */
+	int	outputs;		/* number of outputs */
+};
+
+/*
+DECODER_GET_STATUS returns the following flags.  The only one you need is
+DECODER_STATUS_GOOD, the others are just nice things to know.
+*/
+#define	DECODER_STATUS_GOOD	1	/* receiving acceptable input */
+#define	DECODER_STATUS_COLOR	2	/* receiving color information */
+#define	DECODER_STATUS_PAL	4	/* auto detected */
+#define	DECODER_STATUS_NTSC	8	/* auto detected */
+#define	DECODER_STATUS_SECAM	16	/* auto detected */
+
+
+#define	DECODER_GET_CAPABILITIES _IOR('d', 1, struct video_decoder_capability)
+#define	DECODER_GET_STATUS    	_IOR('d', 2, int)
+#define	DECODER_SET_NORM	_IOW('d', 3, int)
+#define	DECODER_SET_INPUT	_IOW('d', 4, int)	/* 0 <= input < #inputs */
+#define	DECODER_SET_OUTPUT	_IOW('d', 5, int)	/* 0 <= output < #outputs */
+#define	DECODER_ENABLE_OUTPUT	_IOW('d', 6, int)	/* boolean output enable control */
+#define	DECODER_SET_PICTURE   	_IOW('d', 7, struct video_picture)
+
+#define	DECODER_DUMP		_IO('d', 192)		/* debug hook */
+
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/include/linux/video_encoder.h linux/include/linux/video_encoder.h
--- v2.3.9/linux/include/linux/video_encoder.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/video_encoder.h	Mon Jul  5 20:02:10 1999
@@ -0,0 +1,21 @@
+#ifndef _LINUX_VIDEO_ENCODER_H
+#define _LINUX_VIDEO_ENCODER_H
+
+struct video_encoder_capability { /* this name is too long */
+	__u32	flags;
+#define	VIDEO_ENCODER_PAL	1	/* can encode PAL signal */
+#define	VIDEO_ENCODER_NTSC	2	/* can encode NTSC */
+#define	VIDEO_ENCODER_SECAM	4	/* can encode SECAM */
+#define	VIDEO_ENCODER_CCIR	16	/* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+	int	inputs;			/* number of inputs */
+	int	outputs;		/* number of outputs */
+};
+
+#define	ENCODER_GET_CAPABILITIES _IOR('e', 1, struct video_encoder_capability)
+#define	ENCODER_SET_NORM	_IOW('e', 2, int)
+#define	ENCODER_SET_INPUT	_IOW('e', 3, int)	/* 0 <= input < #inputs */
+#define	ENCODER_SET_OUTPUT	_IOW('e', 4, int)	/* 0 <= output < #outputs */
+#define	ENCODER_ENABLE_OUTPUT	_IOW('e', 5, int)	/* boolean output enable control */
+
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.3.9/linux/include/linux/videodev.h	Thu May 13 14:28:30 1999
+++ linux/include/linux/videodev.h	Mon Jul  5 20:02:10 1999
@@ -279,6 +279,7 @@
 #define VID_HARDWARE_VINO	20	/* Reserved for SGI Indy Vino */
 #define VID_HARDWARE_CADET	21	/* Cadet radio */
 #define VID_HARDWARE_CPIA	22
+#define VID_HARDWARE_TERRATEC	23	/* TerraTec ActiveRadio */
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.3.9/linux/include/net/irda/irmod.h linux/include/net/irda/irmod.h
--- v2.3.9/linux/include/net/irda/irmod.h	Wed May 12 13:27:37 1999
+++ linux/include/net/irda/irmod.h	Mon Jul  5 20:02:10 1999
@@ -90,7 +90,7 @@
  */
 struct irda_cb {
 	struct miscdevice dev;	
-	wait_queue_head_t *wait_queue;
+	wait_queue_head_t wait_queue;
 
 	int in_use;
 
diff -u --recursive --new-file v2.3.9/linux/include/net/sock.h linux/include/net/sock.h
--- v2.3.9/linux/include/net/sock.h	Tue Jun 22 14:42:42 1999
+++ linux/include/net/sock.h	Wed Jul  7 09:21:42 1999
@@ -371,10 +371,6 @@
 } while(0);
 
 struct sock {
-	/* This must be first. */
-	struct sock		*sklist_next;
-	struct sock		*sklist_prev;
-
 	/* Local port binding hash linkage. */
 	struct sock		*bind_next;
 	struct sock		**bind_pprev;
@@ -579,10 +575,6 @@
  * transport -> network interface is defined by struct inet_proto
  */
 struct proto {
-	/* These must be first. */
-	struct sock		*sklist_next;
-	struct sock		*sklist_prev;
-
 	void			(*close)(struct sock *sk, 
 					long timeout);
 	int			(*connect)(struct sock *sk,
@@ -621,9 +613,7 @@
 	/* Keeping track of sk's, looking them up, and port selection methods. */
 	void			(*hash)(struct sock *sk);
 	void			(*unhash)(struct sock *sk);
-	void			(*rehash)(struct sock *sk);
-	unsigned short		(*good_socknum)(void);
-	int			(*verify_bind)(struct sock *sk, unsigned short snum);
+	int			(*get_port)(struct sock *sk, unsigned short snum);
 
 	unsigned short		max_header;
 	unsigned long		retransmits;
@@ -666,40 +656,6 @@
 #define SOCKHASH_UNLOCK_READ_BH()	read_unlock(&sockhash_lock)
 #define SOCKHASH_LOCK_WRITE_BH()	write_lock(&sockhash_lock)
 #define SOCKHASH_UNLOCK_WRITE_BH()	write_unlock(&sockhash_lock)
-
-/* Some things in the kernel just want to get at a protocols
- * entire socket list commensurate, thus...
- */
-static __inline__ void add_to_prot_sklist(struct sock *sk)
-{
-	SOCKHASH_LOCK_WRITE();
-	if(!sk->sklist_next) {
-		struct proto *p = sk->prot;
-
-		sk->sklist_prev = (struct sock *) p;
-		sk->sklist_next = p->sklist_next;
-		p->sklist_next->sklist_prev = sk;
-		p->sklist_next = sk;
-
-		/* Charge the protocol. */
-		sk->prot->inuse += 1;
-		if(sk->prot->highestinuse < sk->prot->inuse)
-			sk->prot->highestinuse = sk->prot->inuse;
-	}
-	SOCKHASH_UNLOCK_WRITE();
-}
-
-static __inline__ void del_from_prot_sklist(struct sock *sk)
-{
-	SOCKHASH_LOCK_WRITE();
-	if(sk->sklist_next) {
-		sk->sklist_next->sklist_prev = sk->sklist_prev;
-		sk->sklist_prev->sklist_next = sk->sklist_next;
-		sk->sklist_next = NULL;
-		sk->prot->inuse--;
-	}
-	SOCKHASH_UNLOCK_WRITE();
-}
 
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
diff -u --recursive --new-file v2.3.9/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.9/linux/include/net/tcp.h	Tue Jun 22 14:42:48 1999
+++ linux/include/net/tcp.h	Wed Jul  7 09:21:48 1999
@@ -72,11 +72,7 @@
  */
 struct tcp_bind_bucket {
 	unsigned short		port;
-	unsigned short		flags;
-#define TCPB_FLAG_LOCKED	0x0001
-#define TCPB_FLAG_FASTREUSE	0x0002
-#define TCPB_FLAG_GOODSOCKNUM	0x0004
-
+	unsigned short		fastreuse;
 	struct tcp_bind_bucket	*next;
 	struct sock		*owners;
 	struct tcp_bind_bucket	**pprev;
@@ -115,32 +111,6 @@
 	return (lport & (tcp_bhash_size - 1));
 }
 
-static __inline__ void tcp_sk_bindify(struct sock *sk)
-{
-	struct tcp_bind_bucket *tb;
-	unsigned short snum = sk->num;
-
-	for(tb = tcp_bhash[tcp_bhashfn(snum)]; tb->port != snum; tb = tb->next)
-		;
-	/* Update bucket flags. */
-	if(tb->owners == NULL) {
-		/* We're the first. */
-		if(sk->reuse && sk->state != TCP_LISTEN)
-			tb->flags = TCPB_FLAG_FASTREUSE;
-		else
-			tb->flags = 0;
-	} else {
-		if((tb->flags & TCPB_FLAG_FASTREUSE) &&
-		   ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
-			tb->flags &= ~TCPB_FLAG_FASTREUSE;
-	}
-	if((sk->bind_next = tb->owners) != NULL)
-		tb->owners->bind_pprev = &sk->bind_next;
-	tb->owners = sk;
-	sk->bind_pprev = &tb->owners;
-	sk->prev = (struct sock *) tb;
-}
-
 /* This is a TIME_WAIT bucket.  It works around the memory consumption
  * problems of sockets in such a state on heavily loaded servers, but
  * without violating the protocol specification.
@@ -150,8 +120,6 @@
 	 * XXX Yes I know this is gross, but I'd have to edit every single
 	 * XXX networking file if I created a "struct sock_header". -DaveM
 	 */
-	struct sock		*sklist_next;
-	struct sock		*sklist_prev;
 	struct sock		*bind_next;
 	struct sock		**bind_pprev;
 	__u32			daddr;
@@ -477,7 +445,9 @@
 extern struct proto tcp_prot;
 extern struct tcp_mib tcp_statistics;
 
-extern unsigned short		tcp_good_socknum(void);
+extern void			tcp_put_port(struct sock *sk);
+extern void			__tcp_put_port(struct sock *sk);
+extern void			tcp_inherit_port(struct sock *sk, struct sock *child);
 
 extern void			tcp_v4_err(struct sk_buff *skb,
 					   unsigned char *, int);
@@ -630,8 +600,7 @@
 #define TCP_SLT_SYNACK		0
 #define TCP_SLT_KEEPALIVE	1
 #define TCP_SLT_TWKILL		2
-#define TCP_SLT_BUCKETGC	3
-#define TCP_SLT_MAX		4
+#define TCP_SLT_MAX		3
 
 extern struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX];
  
@@ -1067,17 +1036,6 @@
 	struct tcp_sl_timer *slt = &tcp_slt_array[timer];
 
 	atomic_dec(&slt->count);
-}
-
-/* This needs to use a slow timer, so it is here. */
-static __inline__ void tcp_sk_unbindify(struct sock *sk)
-{
-	struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *) sk->prev;
-	if(sk->bind_next)
-		sk->bind_next->bind_pprev = sk->bind_pprev;
-	*sk->bind_pprev = sk->bind_next;
-	if(tb->owners == NULL)
-		tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
 }
 
 extern const char timer_bug_msg[];
diff -u --recursive --new-file v2.3.9/linux/include/net/udp.h linux/include/net/udp.h
--- v2.3.9/linux/include/net/udp.h	Tue Jun  8 17:58:03 1999
+++ linux/include/net/udp.h	Wed Jul  7 09:21:42 1999
@@ -23,6 +23,7 @@
 #define _UDP_H
 
 #include <linux/udp.h>
+#include <net/sock.h>
 
 #define UDP_HTABLE_SIZE		128
 
@@ -32,7 +33,18 @@
  */
 extern struct sock *udp_hash[UDP_HTABLE_SIZE];
 
-extern unsigned short udp_good_socknum(void);
+extern int udp_port_rover;
+
+static inline int udp_lport_inuse(u16 num)
+{
+	struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)];
+
+	for(; sk != NULL; sk = sk->next) {
+		if(sk->num == num)
+			return 1;
+	}
+	return 0;
+}
 
 /* Note: this must match 'valbool' in sock_setsockopt */
 #define UDP_CSUM_NOXMIT		1
diff -u --recursive --new-file v2.3.9/linux/init/main.c linux/init/main.c
--- v2.3.9/linux/init/main.c	Wed Jun 30 13:38:20 1999
+++ linux/init/main.c	Mon Jul  5 19:52:52 1999
@@ -332,6 +332,9 @@
 #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);
@@ -864,6 +867,9 @@
 #endif
 #ifdef CONFIG_LTPC
 	{ "ltpc=", ltpc_setup },
+#endif
+#ifdef CONFIG_BLK_CPQ_DA
+	{ "smart2=", cpqarray_setup },
 #endif
 	{ 0, 0 }
 };
diff -u --recursive --new-file v2.3.9/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.9/linux/ipc/shm.c	Wed Jun 30 13:38:20 1999
+++ linux/ipc/shm.c	Sat Jul  3 12:04:12 1999
@@ -381,8 +381,7 @@
 	NULL,			/* advise */
 	shm_nopage,		/* nopage */
 	NULL,			/* wppage */
-	shm_swapout,		/* swapout */
-	NULL			/* swapin */
+	shm_swapout		/* swapout */
 };
 
 /* Insert shmd into the list shp->attaches */
@@ -548,6 +547,7 @@
 	unsigned int id;
 	struct shmid_kernel *shp;
 
+	lock_kernel();
 	id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
 	shp = shm_segs[id];
 	if (shp == IPC_UNUSED) {
@@ -558,6 +558,7 @@
 	shp->u.shm_nattch++;
 	shp->u.shm_atime = CURRENT_TIME;
 	shp->u.shm_lpid = current->pid;
+	unlock_kernel();
 }
 
 /*
@@ -571,6 +572,7 @@
 	struct shmid_kernel *shp;
 	int id;
 
+	lock_kernel();
 	/* remove from the list of attaches of the shm segment */
 	id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
 	shp = shm_segs[id];
@@ -579,6 +581,7 @@
 	shp->u.shm_dtime = CURRENT_TIME;
 	if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
 		killseg (id);
+	unlock_kernel();
 }
 
 /*
diff -u --recursive --new-file v2.3.9/linux/kernel/Makefile linux/kernel/Makefile
--- v2.3.9/linux/kernel/Makefile	Wed May  6 11:01:46 1998
+++ linux/kernel/Makefile	Sun Jul  4 13:41:08 1999
@@ -13,7 +13,7 @@
 O_TARGET := kernel.o
 O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
-	    sysctl.o acct.o capability.o
+	    sysctl.o acct.o capability.o ptrace.o
 
 OX_OBJS  += signal.o
 
diff -u --recursive --new-file v2.3.9/linux/kernel/acct.c linux/kernel/acct.c
--- v2.3.9/linux/kernel/acct.c	Wed Jun 30 13:38:20 1999
+++ linux/kernel/acct.c	Sat Jul  3 10:43:52 1999
@@ -276,7 +276,7 @@
 	 */
 	if (!file)
 		return 0;
-	atomic_inc(&file->f_count);
+	get_file(file);
 	if (!check_free_space(file)) {
 		fput(file);
 		return 0;
diff -u --recursive --new-file v2.3.9/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.9/linux/kernel/exit.c	Tue May 11 14:37:40 1999
+++ linux/kernel/exit.c	Sun Jul  4 10:18:52 1999
@@ -166,11 +166,9 @@
 			break;
 		while (set) {
 			if (set & 1) {
-				struct file * file = files->fd[i];
-				if (file) {
-					files->fd[i] = NULL;
+				struct file * file = xchg(&files->fd[i], NULL);
+				if (file)
 					filp_close(file, files);
-				}
 			}
 			i++;
 			set >>= 1;
@@ -182,10 +180,9 @@
 
 static inline void __exit_files(struct task_struct *tsk)
 {
-	struct files_struct * files = tsk->files;
+	struct files_struct * files = xchg(&tsk->files, NULL);
 
 	if (files) {
-		tsk->files = NULL;
 		if (atomic_dec_and_test(&files->count)) {
 			close_files(files);
 			/*
diff -u --recursive --new-file v2.3.9/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.9/linux/kernel/fork.c	Wed Jun 30 13:38:20 1999
+++ linux/kernel/fork.c	Mon Jul  5 20:34:31 1999
@@ -249,16 +249,18 @@
 		tmp->vm_next = NULL;
 		file = tmp->vm_file;
 		if (file) {
-			atomic_inc(&file->f_count);
+			get_file(file);
 			if (tmp->vm_flags & VM_DENYWRITE)
-				file->f_dentry->d_inode->i_writecount--;
+				atomic_dec(&file->f_dentry->d_inode->i_writecount);
       
 			/* insert tmp into the share list, just after mpnt */
+			spin_lock(&file->f_dentry->d_inode->i_shared_lock);
 			if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
 				mpnt->vm_next_share->vm_pprev_share =
 					&tmp->vm_next_share;
 			mpnt->vm_next_share = tmp;
 			tmp->vm_pprev_share = &mpnt->vm_next_share;
+			spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
 		}
 
 		/* Copy the pages, but defer checking for errors */
@@ -304,6 +306,7 @@
 		mm->map_count = 0;
 		mm->def_flags = 0;
 		init_MUTEX_LOCKED(&mm->mmap_sem);
+		mm->page_table_lock = SPIN_LOCK_UNLOCKED;
 		/*
 		 * Leave mm->pgd set to the parent's pgd
 		 * so that pgd_offset() is always valid.
@@ -360,6 +363,10 @@
 	struct mm_struct * mm;
 	int retval;
 
+	tsk->min_flt = tsk->maj_flt = 0;
+	tsk->cmin_flt = tsk->cmaj_flt = 0;
+	tsk->nswap = tsk->cnswap = 0;
+
 	if (clone_flags & CLONE_VM) {
 		mmget(current->mm);
 		/*
@@ -376,9 +383,6 @@
 		goto fail_nomem;
 
 	tsk->mm = mm;
-	tsk->min_flt = tsk->maj_flt = 0;
-	tsk->cmin_flt = tsk->cmaj_flt = 0;
-	tsk->nswap = tsk->cnswap = 0;
 	copy_segments(nr, tsk, mm);
 	retval = new_page_tables(tsk);
 	if (retval)
@@ -478,17 +482,18 @@
 	atomic_set(&newf->count, 1);
 	newf->max_fds = NR_OPEN;
 	newf->fd = new_fds;
+	read_lock(&oldf->file_lock);
 	newf->close_on_exec = oldf->close_on_exec;
 	i = copy_fdset(&newf->open_fds, &oldf->open_fds);
 
 	old_fds = oldf->fd;
 	for (; i != 0; i--) {
 		struct file *f = *old_fds++;
-		*new_fds = f;
 		if (f)
-			atomic_inc(&f->f_count);
-		new_fds++;
+			get_file(f);
+		*new_fds++ = f;
 	}
+	read_unlock(&oldf->file_lock);
 	/* This is long word aligned thus could use a optimized version */ 
 	memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds); 
       
diff -u --recursive --new-file v2.3.9/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.9/linux/kernel/ksyms.c	Wed Jun 30 13:38:20 1999
+++ linux/kernel/ksyms.c	Mon Jul  5 11:45:30 1999
@@ -116,7 +116,8 @@
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(get_fs_type);
 EXPORT_SYMBOL(getname);
-EXPORT_SYMBOL(__fput);
+EXPORT_SYMBOL(__fput);	/* goner? */
+EXPORT_SYMBOL(_fput);
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget);
@@ -141,8 +142,8 @@
 EXPORT_SYMBOL(init_private_file);
 EXPORT_SYMBOL(filp_open);
 EXPORT_SYMBOL(filp_close);
-EXPORT_SYMBOL(fput);
 EXPORT_SYMBOL(put_filp);
+EXPORT_SYMBOL(files_lock);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
@@ -231,6 +232,7 @@
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(max_sectors);
 EXPORT_SYMBOL(max_readahead);
+EXPORT_SYMBOL(file_moveto);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
diff -u --recursive --new-file v2.3.9/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.3.9/linux/kernel/ptrace.c	Wed Dec 31 16:00:00 1969
+++ linux/kernel/ptrace.c	Mon Jul  5 11:30:37 1999
@@ -0,0 +1,163 @@
+/*
+ * linux/kernel/ptrace.c
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Common interfaces for "ptrace()" which we do not want
+ * to continually duplicate across every architecture.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+/*
+ * Access another process' address space, one page at a time.
+ */
+static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
+{
+	pgd_t * pgdir;
+	pmd_t * pgmiddle;
+	pte_t * pgtable;
+	unsigned long page;
+
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (pgd_none(*pgdir))
+		goto fault_in_page;
+	if (pgd_bad(*pgdir))
+		goto bad_pgd;
+	pgmiddle = pmd_offset(pgdir, addr);
+	if (pmd_none(*pgmiddle))
+		goto fault_in_page;
+	if (pmd_bad(*pgmiddle))
+		goto bad_pmd;
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable))
+		goto fault_in_page;
+	page = pte_page(*pgtable);
+	if (MAP_NR(page) >= max_mapnr)
+		return 0;
+	flush_cache_page(vma, addr);
+	{
+		void *src = (void *) (page + (addr & ~PAGE_MASK));
+		void *dst = buf;
+
+		if (write) {
+			dst = src;
+			src = buf;
+		}
+		memcpy(dst, src, len);
+	}
+	flush_page_to_ram(page);
+	return len;
+
+fault_in_page:
+	/* -1: out of memory. 0 - unmapped page */
+	if (handle_mm_fault(tsk, vma, addr, write) > 0)
+		goto repeat;
+	return 0;
+
+bad_pgd:
+	printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pgd_val(*pgdir));
+	return 0;
+
+bad_pmd:
+	printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pmd_val(*pgmiddle));
+	return 0;
+}
+
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+	int copied;
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return 0;
+
+	down(&tsk->mm->mmap_sem);
+	copied = 0;
+	for (;;) {
+		unsigned long offset = addr & ~PAGE_MASK;
+		int this_len = PAGE_SIZE - offset;
+		int retval;
+
+		if (this_len > len)
+			this_len = len;
+		retval = access_one_page(tsk, vma, addr, buf, this_len, write);
+		copied += retval;
+		if (retval != this_len)
+			break;
+
+		len -= retval;
+		if (!len)
+			break;
+
+		addr += retval;
+		buf += retval;
+
+		if (addr < vma->vm_end)
+			continue;	
+		if (!vma->vm_next)
+			break;
+		if (vma->vm_next->vm_start != vma->vm_end)
+			break;
+	
+		vma = vma->vm_next;
+	}
+	up(&tsk->mm->mmap_sem);
+	return copied;
+}
+
+int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
+{
+	int copied = 0;
+
+	while (len > 0) {
+		char buf[128];
+		int this_len, retval;
+
+		this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+		retval = access_process_vm(tsk, src, buf, this_len, 0);
+		if (!retval) {
+			if (copied)
+				break;
+			return -EIO;
+		}
+		if (copy_to_user(dst, buf, retval))
+			return -EFAULT;
+		copied += retval;
+		src += retval;
+		dst += retval;
+		len -= retval;			
+	}
+	return copied;
+}
+
+int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
+{
+	int copied = 0;
+
+	while (len > 0) {
+		char buf[128];
+		int this_len, retval;
+
+		this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+		if (copy_from_user(buf, src, this_len))
+			return -EFAULT;
+		retval = access_process_vm(tsk, dst, buf, this_len, 1);
+		if (!retval) {
+			if (copied)
+				break;
+			return -EIO;
+		}
+		copied += retval;
+		src += retval;
+		dst += retval;
+		len -= retval;			
+	}
+	return copied;
+}
diff -u --recursive --new-file v2.3.9/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.9/linux/kernel/sched.c	Wed May 12 14:41:36 1999
+++ linux/kernel/sched.c	Thu Jul  1 15:09:01 1999
@@ -1465,7 +1465,7 @@
 	unsigned long user = ticks - system;
 	if (p->pid) {
 		p->counter -= ticks;
-		if (p->counter < 0) {
+		if (p->counter <= 0) {
 			p->counter = 0;
 			p->need_resched = 1;
 		}
@@ -1668,7 +1668,7 @@
 	 * do a "normalization" of the priority (traditionally
 	 * Unix nice values are -20 to 20; Linux doesn't really
 	 * use that kind of thing, but uses the length of the
-	 * timeslice instead (default 210 ms). The rounding is
+	 * timeslice instead (default 200 ms). The rounding is
 	 * why we want to avoid negative values.
 	 */
 	newprio = (newprio * DEF_PRIORITY + 10) / 20;
diff -u --recursive --new-file v2.3.9/linux/kernel/signal.c linux/kernel/signal.c
--- v2.3.9/linux/kernel/signal.c	Mon Jun  7 16:14:06 1999
+++ linux/kernel/signal.c	Mon Jul  5 20:02:10 1999
@@ -29,7 +29,7 @@
 
 static kmem_cache_t *signal_queue_cachep;
 
-int nr_queued_signals;
+atomic_t nr_queued_signals;
 int max_queued_signals = 1024;
 
 void __init signals_init(void)
@@ -60,7 +60,7 @@
 	while (q) {
 		n = q->next;
 		kmem_cache_free(signal_queue_cachep, q);
-		nr_queued_signals--;
+		atomic_dec(&nr_queued_signals);
 		q = n;
 	}
 }
@@ -157,7 +157,7 @@
 					current->sigqueue_tail = pp;
 				*info = q->info;
 				kmem_cache_free(signal_queue_cachep,q);
-				nr_queued_signals--;
+				atomic_dec(&nr_queued_signals);
 				
 				/* then see if this signal is still pending. */
 				q = *pp;
@@ -323,13 +323,13 @@
 
 		struct signal_queue *q = 0;
 
-		if (nr_queued_signals < max_queued_signals) {
+		if (atomic_read(&nr_queued_signals) < max_queued_signals) {
 			q = (struct signal_queue *)
 			    kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
 		}
 		
 		if (q) {
-			nr_queued_signals++;
+			atomic_inc(&nr_queued_signals);
 			q->next = NULL;
 			*t->sigqueue_tail = q;
 			t->sigqueue_tail = &q->next;
@@ -872,7 +872,7 @@
 					else {
 						*pp = q->next;
 						kmem_cache_free(signal_queue_cachep, q);
-						nr_queued_signals--;
+						atomic_dec(&nr_queued_signals);
 					}
 					q = *pp;
 				}
@@ -1067,7 +1067,9 @@
 
 	return old;
 }
+#endif /* !defined(__alpha__) */
 
+#if !defined(__alpha__) && !defined(__mips__)
 /*
  * For backwards compatibility.  Functionality superseded by sigaction.
  */
@@ -1084,4 +1086,4 @@
 
 	return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
 }
-#endif /* !alpha && !__ia64__ */
+#endif /* !alpha && !__ia64__ && !defined(__mips__) */
diff -u --recursive --new-file v2.3.9/linux/kernel/sys.c linux/kernel/sys.c
--- v2.3.9/linux/kernel/sys.c	Mon Jun  7 16:17:59 1999
+++ linux/kernel/sys.c	Sat Jul  3 12:04:12 1999
@@ -930,6 +930,8 @@
  * either stopped or zombied.  In the zombied case the task won't get
  * reaped till shortly after the call to getrusage(), in both cases the
  * task being examined is in a frozen state so the counters won't change.
+ *
+ * FIXME! Get the fault counts properly!
  */
 int getrusage(struct task_struct *p, int who, struct rusage *ru)
 {
diff -u --recursive --new-file v2.3.9/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.9/linux/kernel/sysctl.c	Wed Jun 30 13:38:20 1999
+++ linux/kernel/sysctl.c	Mon Jul  5 20:35:18 1999
@@ -18,7 +18,6 @@
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
-#include <linux/swapctl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
diff -u --recursive --new-file v2.3.9/linux/lib/string.c linux/lib/string.c
--- v2.3.9/linux/lib/string.c	Wed Jun 30 13:38:20 1999
+++ linux/lib/string.c	Mon Jul  5 20:02:10 1999
@@ -362,3 +362,17 @@
 	return NULL;
 }
 #endif
+
+#ifndef __HAVE_ARCH_MEMCHR
+void *memchr(const void *s, int c, size_t n)
+{
+	unsigned char *p = s;
+	while (n-- != 0) {
+        	if ((unsigned char)c == *p++) {
+			return p-1;
+		}
+	}
+	return NULL;
+}
+
+#endif
diff -u --recursive --new-file v2.3.9/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.9/linux/mm/filemap.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/filemap.c	Tue Jul  6 10:11:40 1999
@@ -1194,8 +1194,6 @@
 	struct file * in_file, * out_file;
 	struct inode * in_inode, * out_inode;
 
-	lock_kernel();
-
 	/*
 	 * Get input file, and verify that it is ok..
 	 */
@@ -1234,7 +1232,6 @@
 	if (retval)
 		goto fput_out;
 
-	unlock_kernel();
 	retval = 0;
 	if (count) {
 		read_descriptor_t desc;
@@ -1244,7 +1241,7 @@
 		ppos = &in_file->f_pos;
 		if (offset) {
 			if (get_user(pos, offset))
-				goto fput_out_lock;
+				goto fput_out;
 			ppos = &pos;
 		}
 
@@ -1261,14 +1258,11 @@
 			put_user(pos, offset);
 	}
 
-fput_out_lock:
-	lock_kernel();
 fput_out:
 	fput(out_file);
 fput_in:
 	fput(in_file);
 out:
-	unlock_kernel();
 	return retval;
 }
 
@@ -1297,9 +1291,7 @@
 	new_page = 0;
 	offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
 	if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
-		goto no_page_nolock;
-
-	unlock_kernel();
+		goto no_page;
 
 	/*
 	 * Do we have something in the page cache already?
@@ -1344,7 +1336,6 @@
 			page_cache_free(new_page);
 
 		flush_page_to_ram(old_page);
-		lock_kernel();
 		return old_page;
 	}
 
@@ -1354,7 +1345,6 @@
 	copy_page(new_page, old_page);
 	flush_page_to_ram(new_page);
 	page_cache_release(page);
-	lock_kernel();
 	return new_page;
 
 no_cached_page:
@@ -1431,8 +1421,6 @@
 	if (new_page)
 		page_cache_free(new_page);
 no_page:
-	lock_kernel();
-no_page_nolock:
 	return 0;
 }
 
@@ -1487,7 +1475,7 @@
 	 * If a task terminates while we're swapping the page, the vma and
 	 * and file could be released ... increment the count to be safe.
 	 */
-	atomic_inc(&file->f_count);
+	get_file(file);
 	result = do_write_page(inode, file, (const char *) page, offset);
 	fput(file);
 	return result;
@@ -1648,8 +1636,7 @@
 	NULL,			/* advise */
 	filemap_nopage,		/* nopage */
 	NULL,			/* wppage */
-	filemap_swapout,	/* swapout */
-	NULL,			/* swapin */
+	filemap_swapout		/* swapout */
 };
 
 /*
@@ -1667,8 +1654,7 @@
 	NULL,			/* advise */
 	filemap_nopage,		/* nopage */
 	NULL,			/* wppage */
-	NULL,			/* swapout */
-	NULL,			/* swapin */
+	NULL			/* swapout */
 };
 
 /* This is used for a general mmap of a disk file */
diff -u --recursive --new-file v2.3.9/linux/mm/memory.c linux/mm/memory.c
--- v2.3.9/linux/mm/memory.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/memory.c	Tue Jul  6 23:06:05 1999
@@ -36,7 +36,9 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
+#include <linux/pagemap.h>
 #include <linux/smp_lock.h>
+#include <linux/swapctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -320,7 +322,7 @@
 	}
 }
 
-static inline int zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+static inline int zap_pte_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size)
 {
 	pte_t * pte;
 	int freed;
@@ -345,15 +347,15 @@
 		page = *pte;
 		pte++;
 		size--;
+		pte_clear(pte-1);
 		if (pte_none(page))
 			continue;
-		pte_clear(pte-1);
 		freed += free_pte(page);
 	}
 	return freed;
 }
 
-static inline int zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+static inline int zap_pmd_range(struct mm_struct *mm, pgd_t * dir, unsigned long address, unsigned long size)
 {
 	pmd_t * pmd;
 	unsigned long end;
@@ -373,7 +375,7 @@
 		end = PGDIR_SIZE;
 	freed = 0;
 	do {
-		freed += zap_pte_range(pmd, address, end - address);
+		freed += zap_pte_range(mm, pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK; 
 		pmd++;
 	} while (address < end);
@@ -390,11 +392,21 @@
 	int freed = 0;
 
 	dir = pgd_offset(mm, address);
+
+	/*
+	 * This is a long-lived spinlock. That's fine.
+	 * There's no contention, because the page table
+	 * lock only protects against kswapd anyway, and
+	 * even if kswapd happened to be looking at this
+	 * process we _want_ it to get stuck.
+	 */
+	spin_lock(&mm->page_table_lock);
 	while (address < end) {
-		freed += zap_pmd_range(dir, address, end - address);
+		freed += zap_pmd_range(mm, dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
+	spin_unlock(&mm->page_table_lock);
 	/*
 	 * Update rss for the mm_struct (not necessarily current->mm)
 	 */
@@ -599,17 +611,16 @@
  * We also mark the page dirty at this point even though the page will
  * change only once the write actually happens. This avoids a few races,
  * and potentially makes it more efficient.
+ *
+ * We enter with the page table read-lock held, and need to exit without
+ * it.
  */
 static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
 	unsigned long address, pte_t *page_table, pte_t pte)
 {
 	unsigned long old_page, new_page;
 	struct page * page;
-	
-	new_page = __get_free_page(GFP_USER);
-	/* Did swap_out() unmap the protected page while we slept? */
-	if (pte_val(*page_table) != pte_val(pte))
-		goto end_wp_page;
+
 	old_page = pte_page(pte);
 	if (MAP_NR(old_page) >= max_mapnr)
 		goto bad_wp_page;
@@ -634,44 +645,44 @@
 		/* FallThrough */
 	case 1:
 		flush_cache_page(vma, address);
-		set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
+		set_pte(page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
 		flush_tlb_page(vma, address);
-end_wp_page:
-		/*
-		 * We can release the kernel lock now.. Now swap_out will see
-		 * a dirty page and so won't get confused and flush_tlb_page
-		 * won't SMP race. -Andrea
-		 */
-		unlock_kernel();
-
-		if (new_page)
-			free_page(new_page);
+		spin_unlock(&tsk->mm->page_table_lock);
 		return 1;
 	}
-		
+
+	/*
+	 * Ok, we need to copy. Oh, well..
+	 */
+	spin_unlock(&tsk->mm->page_table_lock);
+	new_page = __get_free_page(GFP_USER);
 	if (!new_page)
-		goto no_new_page;
+		return -1;
+	spin_lock(&tsk->mm->page_table_lock);
 
-	if (PageReserved(page))
-		++vma->vm_mm->rss;
-	copy_cow_page(old_page,new_page);
-	flush_page_to_ram(old_page);
-	flush_page_to_ram(new_page);
-	flush_cache_page(vma, address);
-	set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
-	flush_tlb_page(vma, address);
-	unlock_kernel();
-	__free_page(page);
+	/*
+	 * Re-check the pte - we dropped the lock
+	 */
+	if (pte_val(*page_table) == pte_val(pte)) {
+		if (PageReserved(page))
+			++vma->vm_mm->rss;
+		copy_cow_page(old_page,new_page);
+		flush_page_to_ram(old_page);
+		flush_page_to_ram(new_page);
+		flush_cache_page(vma, address);
+		set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
+		flush_tlb_page(vma, address);
+
+		/* Free the old page.. */
+		new_page = old_page;
+	}
+	spin_unlock(&tsk->mm->page_table_lock);
+	free_page(new_page);
 	return 1;
 
 bad_wp_page:
 	printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
-	send_sig(SIGKILL, tsk, 1);
-no_new_page:
-	unlock_kernel();
-	if (new_page)
-		free_page(new_page);
-	return 0;
+	return -1;
 }
 
 /*
@@ -725,8 +736,9 @@
 	struct vm_area_struct * mpnt;
 
 	truncate_inode_pages(inode, offset);
+	spin_lock(&inode->i_shared_lock);
 	if (!inode->i_mmap)
-		return;
+		goto out_unlock;
 	mpnt = inode->i_mmap;
 	do {
 		struct mm_struct *mm = mpnt->vm_mm;
@@ -757,35 +769,81 @@
 		zap_page_range(mm, start, len);
 		flush_tlb_range(mm, start, end);
 	} while ((mpnt = mpnt->vm_next_share) != NULL);
+out_unlock:
+	spin_unlock(&inode->i_shared_lock);
 }
 
 
-/*
- * This is called with the kernel lock held, we need
- * to return without it.
+
+/* 
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time.  We also make sure to queue
+ * the 'original' request together with the readahead ones...  
  */
-static int do_swap_page(struct task_struct * tsk, 
+static void swapin_readahead(unsigned long entry)
+{
+	int i;
+	struct page *new_page;
+	unsigned long offset = SWP_OFFSET(entry);
+	struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
+	
+	offset = (offset >> page_cluster) << page_cluster;
+
+	i = 1 << page_cluster;
+	do {
+		/* Don't read-ahead past the end of the swap area */
+		if (offset >= swapdev->max)
+			break;
+		/* Don't block on I/O for read-ahead */
+		if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
+			break;
+		/* Don't read in bad or busy pages */
+		if (!swapdev->swap_map[offset])
+			break;
+		if (swapdev->swap_map[offset] == SWAP_MAP_BAD)
+			break;
+
+		/* Ok, do the async read-ahead now */
+		new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
+		if (new_page != NULL)
+			__free_page(new_page);
+		offset++;
+	} while (--i);
+	return;
+}
+
+static int do_swap_page(struct task_struct * tsk,
 	struct vm_area_struct * vma, unsigned long address,
-	pte_t * page_table, pte_t entry, int write_access)
+	pte_t * page_table, unsigned long entry, int write_access)
 {
-	if (!vma->vm_ops || !vma->vm_ops->swapin) {
-		swap_in(tsk, vma, page_table, pte_val(entry), write_access);
-		flush_page_to_ram(pte_page(*page_table));
-	} else {
-		pte_t page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry));
-		if (pte_val(*page_table) != pte_val(entry)) {
-			free_page(pte_page(page));
-		} else {
-			if (page_count(mem_map + MAP_NR(pte_page(page))) > 1 &&
-			    !(vma->vm_flags & VM_SHARED))
-				page = pte_wrprotect(page);
-			++vma->vm_mm->rss;
-			++tsk->maj_flt;
-			flush_page_to_ram(pte_page(page));
-			set_pte(page_table, page);
-		}
+	struct page *page = lookup_swap_cache(entry);
+	pte_t pte;
+
+	if (!page) {
+		lock_kernel();
+		swapin_readahead(entry);
+		page = read_swap_cache(entry);
+		unlock_kernel();
+		if (!page)
+			return -1;
+
+		flush_page_to_ram(page_address(page));
+	}
+
+	vma->vm_mm->rss++;
+	tsk->min_flt++;
+	swap_free(entry);
+
+	pte = mk_pte(page_address(page), vma->vm_page_prot);
+
+	if (write_access && !is_page_shared(page)) {
+		delete_from_swap_cache(page);
+		pte = pte_mkwrite(pte_mkdirty(pte));
 	}
-	unlock_kernel();
+	set_pte(page_table, pte);
+	/* No need to invalidate - it was non-present before */
+	update_mmu_cache(vma, address, pte);
 	return 1;
 }
 
@@ -798,7 +856,7 @@
 	if (write_access) {
 		unsigned long page = __get_free_page(GFP_USER);
 		if (!page)
-			return 0;
+			return -1;
 		clear_page(page);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 		vma->vm_mm->rss++;
@@ -806,6 +864,8 @@
 		flush_page_to_ram(page);
 	}
 	set_pte(page_table, entry);
+	/* No need to invalidate - it was non-present before */
+	update_mmu_cache(vma, addr, entry);
 	return 1;
 }
 
@@ -827,23 +887,17 @@
 	unsigned long page;
 	pte_t entry;
 
-	if (!vma->vm_ops || !vma->vm_ops->nopage) {
-		unlock_kernel();
-		return do_anonymous_page(tsk, vma, page_table, write_access,
-		                         address);
-	}
+	if (!vma->vm_ops || !vma->vm_ops->nopage)
+		return do_anonymous_page(tsk, vma, page_table, write_access, address);
 
 	/*
 	 * The third argument is "no_share", which tells the low-level code
 	 * to copy, not share the page even if sharing is possible.  It's
 	 * essentially an early COW detection.
 	 */
-	page = vma->vm_ops->nopage(vma, address & PAGE_MASK,
-		(vma->vm_flags & VM_SHARED)?0:write_access);
-
-	unlock_kernel();
+	page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
 	if (!page)
-		return 0;
+		return 0;	/* SIGBUS - but we _really_ should know whether it is OOM or SIGBUS */
 
 	++tsk->maj_flt;
 	++vma->vm_mm->rss;
@@ -866,6 +920,7 @@
 		entry = pte_wrprotect(entry);
 	set_pte(page_table, entry);
 	/* no need to invalidate: a not-present page shouldn't be cached */
+	update_mmu_cache(vma, address, entry);
 	return 1;
 }
 
@@ -877,6 +932,15 @@
  * There is also a hook called "update_mmu_cache()" that architectures
  * with external mmu caches can use to update those (ie the Sparc or
  * PowerPC hashed page tables that act as extended TLBs).
+ *
+ * Note the "page_table_lock". It is to protect against kswapd removing
+ * pages from under us. Note that kswapd only ever _removes_ pages, never
+ * adds them. As such, once we have noticed that the page is not present,
+ * we can drop the lock early.
+ *
+ * The adding of pages is protected by the MM semaphore (which we hold),
+ * so we don't need to worry about a page being suddenly been added into
+ * our VM.
  */
 static inline int handle_pte_fault(struct task_struct *tsk,
 	struct vm_area_struct * vma, unsigned long address,
@@ -884,27 +948,32 @@
 {
 	pte_t entry;
 
-	lock_kernel();
 	entry = *pte;
-
 	if (!pte_present(entry)) {
 		if (pte_none(entry))
 			return do_no_page(tsk, vma, address, write_access, pte);
-		return do_swap_page(tsk, vma, address, pte, entry, write_access);
+		return do_swap_page(tsk, vma, address, pte, pte_val(entry), write_access);
 	}
 
-	entry = pte_mkyoung(entry);
-	set_pte(pte, entry);
-	flush_tlb_page(vma, address);
-	if (write_access) {
-		if (!pte_write(entry))
-			return do_wp_page(tsk, vma, address, pte, entry);
+	/*
+	 * Ok, the entry was present, we need to get the page table
+	 * lock to synchronize with kswapd, and verify that the entry
+	 * didn't change from under us..
+	 */
+	spin_lock(&tsk->mm->page_table_lock);
+	if (pte_val(entry) == pte_val(*pte)) {
+		if (write_access) {
+			if (!pte_write(entry))
+				return do_wp_page(tsk, vma, address, pte, entry);
 
-		entry = pte_mkdirty(entry);
+			entry = pte_mkdirty(entry);
+		}
+		entry = pte_mkyoung(entry);
 		set_pte(pte, entry);
 		flush_tlb_page(vma, address);
+		update_mmu_cache(vma, address, entry);
 	}
-	unlock_kernel();
+	spin_unlock(&tsk->mm->page_table_lock);
 	return 1;
 }
 
@@ -921,28 +990,27 @@
 	pmd = pmd_alloc(pgd, address);
 	if (pmd) {
 		pte_t * pte = pte_alloc(pmd, address);
-		if (pte) {
-			if (handle_pte_fault(tsk, vma, address, write_access, pte)) {
-				update_mmu_cache(vma, address, *pte);
-				return 1;
-			}
-		}
+		if (pte)
+			return handle_pte_fault(tsk, vma, address, write_access, pte);
 	}
-	return 0;
+	return -1;
 }
 
 /*
  * Simplistic page force-in..
  */
-void make_pages_present(unsigned long addr, unsigned long end)
+int make_pages_present(unsigned long addr, unsigned long end)
 {
 	int write;
+	struct task_struct *tsk = current;
 	struct vm_area_struct * vma;
 
-	vma = find_vma(current->mm, addr);
+	vma = find_vma(tsk->mm, addr);
 	write = (vma->vm_flags & VM_WRITE) != 0;
 	while (addr < end) {
-		handle_mm_fault(current, vma, addr, write);
+		if (handle_mm_fault(tsk, vma, addr, write) < 0)
+			return -1;
 		addr += PAGE_SIZE;
 	}
+	return 0;
 }
diff -u --recursive --new-file v2.3.9/linux/mm/mlock.c linux/mm/mlock.c
--- v2.3.9/linux/mm/mlock.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/mlock.c	Tue Jul  6 10:11:40 1999
@@ -31,7 +31,7 @@
 	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_file)
-		atomic_inc(&n->vm_file->f_count);
+		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -52,7 +52,7 @@
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_file)
-		atomic_inc(&n->vm_file->f_count);
+		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -179,7 +179,6 @@
 	int error = -ENOMEM;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
 	len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 	start &= PAGE_MASK;
 
@@ -200,7 +199,6 @@
 
 	error = do_mlock(start, len, 1);
 out:
-	unlock_kernel();
 	up(&current->mm->mmap_sem);
 	return error;
 }
@@ -210,11 +208,9 @@
 	int ret;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
 	len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 	start &= PAGE_MASK;
 	ret = do_mlock(start, len, 0);
-	unlock_kernel();
 	up(&current->mm->mmap_sem);
 	return ret;
 }
@@ -254,7 +250,6 @@
 	int ret = -EINVAL;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
 	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 		goto out;
 
@@ -272,7 +267,6 @@
 
 	ret = do_mlockall(flags);
 out:
-	unlock_kernel();
 	up(&current->mm->mmap_sem);
 	return ret;
 }
@@ -282,9 +276,7 @@
 	int ret;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
 	ret = do_mlockall(0);
-	unlock_kernel();
 	up(&current->mm->mmap_sem);
 	return ret;
 }
diff -u --recursive --new-file v2.3.9/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.9/linux/mm/mmap.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/mmap.c	Tue Jul  6 10:11:40 1999
@@ -77,10 +77,12 @@
 
 	if (file) {
 		if (vma->vm_flags & VM_DENYWRITE)
-			file->f_dentry->d_inode->i_writecount++;
+			atomic_inc(&file->f_dentry->d_inode->i_writecount);
+		spin_lock(&file->f_dentry->d_inode->i_shared_lock);
 		if(vma->vm_next_share)
 			vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
 		*vma->vm_pprev_share = vma->vm_next_share;
+		spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
 	}
 }
 
@@ -294,7 +296,7 @@
 	if (file) {
 		int correct_wcount = 0;
 		if (vma->vm_flags & VM_DENYWRITE) {
-			if (file->f_dentry->d_inode->i_writecount > 0) {
+			if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
 				error = -ETXTBSY;
 				goto free_vma;
 			}
@@ -303,17 +305,17 @@
 			 * might). In any case, this takes care of any
 			 * race that this might cause.
 			 */
-			file->f_dentry->d_inode->i_writecount--;
+			atomic_dec(&file->f_dentry->d_inode->i_writecount);
 			correct_wcount = 1;
 		}
 		error = file->f_op->mmap(file, vma);
 		/* Fix up the count if necessary, then check for an error */
 		if (correct_wcount)
-			file->f_dentry->d_inode->i_writecount++;
+			atomic_inc(&file->f_dentry->d_inode->i_writecount);
 		if (error)
 			goto unmap_and_free_vma;
 		vma->vm_file = file;
-		atomic_inc(&file->f_count);
+		get_file(file);
 	}
 
 	/*
@@ -547,7 +549,7 @@
 		mpnt->vm_file = area->vm_file;
 		mpnt->vm_pte = area->vm_pte;
 		if (mpnt->vm_file)
-			atomic_inc(&mpnt->vm_file->f_count);
+			get_file(mpnt->vm_file);
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
@@ -678,9 +680,9 @@
 		size = end - st;
 
 		lock_kernel();
-
 		if (mpnt->vm_ops && mpnt->vm_ops->unmap)
 			mpnt->vm_ops->unmap(mpnt, st, size);
+		unlock_kernel();
 
 		remove_shared_vm_struct(mpnt);
 		mm->map_count--;
@@ -693,8 +695,6 @@
 		 * Fix the mapping, and free the old area if it wasn't reused.
 		 */
 		extra = unmap_fixup(mpnt, st, size, extra);
-
-		unlock_kernel();
 	}
 
 	/* Release the extra vma struct if it wasn't used */
@@ -787,10 +787,8 @@
 	flags = vma->vm_flags;
 	addr = vma->vm_start;
 
-	lock_kernel();		/* kswapd, ugh */
 	insert_vm_struct(mm, vma);
 	merge_segments(mm, vma->vm_start, vma->vm_end);
-	unlock_kernel();
 	
 	mm->total_vm += len >> PAGE_SHIFT;
 	if (flags & VM_LOCKED) {
@@ -878,13 +876,15 @@
 	if (file) {
 		struct inode * inode = file->f_dentry->d_inode;
 		if (vmp->vm_flags & VM_DENYWRITE)
-			inode->i_writecount--;
+			atomic_dec(&inode->i_writecount);
       
 		/* insert vmp into inode's share list */
+		spin_lock(&inode->i_shared_lock);
 		if((vmp->vm_next_share = inode->i_mmap) != NULL)
 			inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
 		inode->i_mmap = vmp;
 		vmp->vm_pprev_share = &inode->i_mmap;
+		spin_unlock(&inode->i_shared_lock);
 	}
 }
 
diff -u --recursive --new-file v2.3.9/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.3.9/linux/mm/mprotect.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/mprotect.c	Tue Jul  6 10:11:40 1999
@@ -103,7 +103,7 @@
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_file)
-		atomic_inc(&n->vm_file->f_count);
+		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -126,7 +126,7 @@
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_file)
-		atomic_inc(&n->vm_file->f_count);
+		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -212,7 +212,6 @@
 		return 0;
 
 	down(&current->mm->mmap_sem);
-	lock_kernel();
 
 	vma = find_vma(current->mm, start);
 	error = -EFAULT;
@@ -249,7 +248,6 @@
 	}
 	merge_segments(current->mm, start, end);
 out:
-	unlock_kernel();
 	up(&current->mm->mmap_sem);
 	return error;
 }
diff -u --recursive --new-file v2.3.9/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.9/linux/mm/mremap.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/mremap.c	Tue Jul  6 21:43:08 1999
@@ -57,11 +57,13 @@
 	return pte;
 }
 
-static inline int copy_one_pte(pte_t * src, pte_t * dst)
+static inline int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst)
 {
 	int error = 0;
-	pte_t pte = *src;
+	pte_t pte;
 
+	spin_lock(&mm->page_table_lock);
+	pte = *src;
 	if (!pte_none(pte)) {
 		error++;
 		if (dst) {
@@ -70,6 +72,7 @@
 			error--;
 		}
 	}
+	spin_unlock(&mm->page_table_lock);
 	return error;
 }
 
@@ -80,7 +83,7 @@
 
 	src = get_one_pte(mm, old_addr);
 	if (src)
-		error = copy_one_pte(src, alloc_one_pte(mm, new_addr));
+		error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr));
 	return error;
 }
 
@@ -134,14 +137,12 @@
 			new_vma->vm_start = new_addr;
 			new_vma->vm_end = new_addr+new_len;
 			new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
-			lock_kernel();
 			if (new_vma->vm_file)
-				atomic_inc(&new_vma->vm_file->f_count);
+				get_file(new_vma->vm_file);
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
 			insert_vm_struct(current->mm, new_vma);
 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
-			unlock_kernel();
 			do_munmap(addr, old_len);
 			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			if (new_vma->vm_flags & VM_LOCKED) {
diff -u --recursive --new-file v2.3.9/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.9/linux/mm/page_alloc.c	Tue Jun 22 10:50:36 1999
+++ linux/mm/page_alloc.c	Fri Jul  2 15:10:36 1999
@@ -345,90 +345,3 @@
 	}
 	return start_mem;
 }
-
-/* 
- * Primitive swap readahead code. We simply read an aligned block of
- * (1 << page_cluster) entries in the swap area. This method is chosen
- * because it doesn't cost us any seek time.  We also make sure to queue
- * the 'original' request together with the readahead ones...  
- */
-void swapin_readahead(unsigned long entry)
-{
-	int i;
-	struct page *new_page;
-	unsigned long offset = SWP_OFFSET(entry);
-	struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
-	
-	offset = (offset >> page_cluster) << page_cluster;
-
-	i = 1 << page_cluster;
-	do {
-		/* Don't read-ahead past the end of the swap area */
-		if (offset >= swapdev->max)
-			break;
-		/* Don't block on I/O for read-ahead */
-		if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
-			break;
-		/* Don't read in bad or busy pages */
-		if (!swapdev->swap_map[offset])
-			break;
-		if (swapdev->swap_map[offset] == SWAP_MAP_BAD)
-			break;
-
-		/* Ok, do the async read-ahead now */
-		new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
-		if (new_page != NULL)
-			__free_page(new_page);
-		offset++;
-	} while (--i);
-	return;
-}
-
-/*
- * The tests may look silly, but it essentially makes sure that
- * no other process did a swap-in on us just as we were waiting.
- *
- * Also, don't bother to add to the swap cache if this page-in
- * was due to a write access.
- */
-void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
-	pte_t * page_table, unsigned long entry, int write_access)
-{
-	unsigned long page;
-	struct page *page_map = lookup_swap_cache(entry);
-
-	if (!page_map) {
-		swapin_readahead(entry);
-		page_map = read_swap_cache(entry);
-	}
-	if (pte_val(*page_table) != entry) {
-		if (page_map)
-			free_page_and_swap_cache(page_address(page_map));
-		return;
-	}
-	if (!page_map) {
-		set_pte(page_table, BAD_PAGE);
-		swap_free(entry);
-		oom(tsk);
-		return;
-	}
-
-	page = page_address(page_map);
-	vma->vm_mm->rss++;
-	tsk->min_flt++;
-	swap_free(entry);
-
-	if (!write_access || is_page_shared(page_map)) {
-		set_pte(page_table, mk_pte(page, vma->vm_page_prot));
-		return;
-	}
-
-	/*
-	 * The page is unshared and we're going to dirty it - so tear
-	 * down the swap cache and give exclusive access to the page to
-	 * this process.
-	 */
-	delete_from_swap_cache(page_map);
-	set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
-  	return;
-}
diff -u --recursive --new-file v2.3.9/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.9/linux/mm/vmscan.c	Tue Jun 22 14:36:36 1999
+++ linux/mm/vmscan.c	Sat Jul  3 12:04:12 1999
@@ -45,7 +45,11 @@
 	page_addr = pte_page(pte);
 	if (MAP_NR(page_addr) >= max_mapnr)
 		goto out_failed;
+
 	page = mem_map + MAP_NR(page_addr);
+	spin_lock(&tsk->mm->page_table_lock);
+	if (pte_val(pte) != pte_val(*page_table))
+		goto out_failed_unlock;
 
 	/*
 	 * Dont be too eager to get aging right if
@@ -58,13 +62,13 @@
 		 */
 		set_pte(page_table, pte_mkold(pte));
 		set_bit(PG_referenced, &page->flags);
-		goto out_failed;
+		goto out_failed_unlock;
 	}
 
 	if (PageReserved(page)
 	    || PageLocked(page)
 	    || ((gfp_mask & __GFP_DMA) && !PageDMA(page)))
-		goto out_failed;
+		goto out_failed_unlock;
 
 	/*
 	 * Is the page already in the swap cache? If so, then
@@ -82,7 +86,7 @@
 		vma->vm_mm->rss--;
 		flush_tlb_page(vma, address);
 		__free_page(page);
-		goto out_failed;
+		goto out_failed_unlock;
 	}
 
 	/*
@@ -109,7 +113,7 @@
 	 * locks etc.
 	 */
 	if (!(gfp_mask & __GFP_IO))
-		goto out_failed;
+		goto out_failed_unlock;
 
 	/*
 	 * Ok, it's really dirty. That means that
@@ -134,6 +138,7 @@
 	if (vma->vm_ops && vma->vm_ops->swapout) {
 		pid_t pid = tsk->pid;
 		pte_clear(page_table);
+		spin_unlock(&tsk->mm->page_table_lock);
 		flush_tlb_page(vma, address);
 		vma->vm_mm->rss--;
 		
@@ -155,6 +160,8 @@
 	vma->vm_mm->rss--;
 	tsk->nswap++;
 	set_pte(page_table, __pte(entry));
+	spin_unlock(&tsk->mm->page_table_lock);
+
 	flush_tlb_page(vma, address);
 	swap_duplicate(entry);	/* One for the process, one for the swap cache */
 
@@ -167,6 +174,8 @@
 out_free_success:
 	__free_page(page);
 	return 1;
+out_failed_unlock:
+	spin_unlock(&tsk->mm->page_table_lock);
 out_failed:
 	return 0;
 }
diff -u --recursive --new-file v2.3.9/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.3.9/linux/net/appletalk/ddp.c	Fri Mar 26 14:01:40 1999
+++ linux/net/appletalk/ddp.c	Mon Jul  5 20:03:14 1999
@@ -894,7 +894,7 @@
 			else
 			{
 				limit = ntohs(nr->nr_lastnet);
-				if(limit - ntohs(nr->nr_firstnet) > 256)
+				if(limit - ntohs(nr->nr_firstnet) > 4096)
 				{
 					printk(KERN_WARNING "Too many routes/iface.\n");
 					return (-EINVAL);
@@ -938,6 +938,8 @@
                                 return (-EPERM);
                         if(sa->sat_family != AF_APPLETALK)
                                 return (-EINVAL);
+                        if (atif == NULL)
+                                return (-EADDRNOTAVAIL);
 
                         /*
                          * for now, we only support proxy AARP on ELAP;
@@ -987,6 +989,8 @@
                                 return (-EPERM);
                         if(sa->sat_family != AF_APPLETALK)
                                 return (-EINVAL);
+                        if (atif == NULL)
+                                return (-EADDRNOTAVAIL);
 
                         /*
                          * give to aarp module to remove proxy entry
diff -u --recursive --new-file v2.3.9/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.3.9/linux/net/ax25/af_ax25.c	Sun Mar  7 15:25:23 1999
+++ linux/net/ax25/af_ax25.c	Mon Jul  5 20:03:14 1999
@@ -462,6 +462,9 @@
 	if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
 		return -ENODEV;
 
+	if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
+		return -EINVAL;
+
 	digi.ndigi = ax25_ctl.digi_count;
 	for (k = 0; k < digi.ndigi; k++)
 		digi.calls[k] = ax25_ctl.digi_addr[k];
diff -u --recursive --new-file v2.3.9/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.3.9/linux/net/bridge/br.c	Sun Mar  7 15:25:23 1999
+++ linux/net/bridge/br.c	Mon Jul  5 20:03:14 1999
@@ -1831,12 +1831,8 @@
 			
 /*			printk("Flood to port %d\n",i);*/
 			nskb->nh.raw = nskb->data + ETH_HLEN;
-#if LINUX_VERSION_CODE >= 0x20100
 			nskb->priority = 1;
 			dev_queue_xmit(nskb);
-#else
-			dev_queue_xmit(nskb,nskb->dev,1);
-#endif
 		}
 	}
 	return(0);
diff -u --recursive --new-file v2.3.9/linux/net/core/scm.c linux/net/core/scm.c
--- v2.3.9/linux/net/core/scm.c	Wed Jun 30 13:38:20 1999
+++ linux/net/core/scm.c	Sat Jul  3 10:43:11 1999
@@ -232,8 +232,8 @@
 			break;
 		}
 		/* Bump the usage count and install the file. */
-		atomic_inc(&fp[i]->f_count);
-		current->files->fd[new_fd] = fp[i];
+		get_file(fp[i]);
+		fd_install(new_fd, fp[i]);
 	}
 
 	if (i > 0)
@@ -271,10 +271,9 @@
 
 	new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL);
 	if (new_fpl) {
-		memcpy(new_fpl, fpl, sizeof(*fpl));
-
 		for (i=fpl->count-1; i>=0; i--)
-			atomic_inc(&fpl->fp[i]->f_count);
+			get_file(fpl->fp[i]);
+		memcpy(new_fpl, fpl, sizeof(*fpl));
 	}
 	return new_fpl;
 }
diff -u --recursive --new-file v2.3.9/linux/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- v2.3.9/linux/net/decnet/dn_fib.c	Wed May 26 09:36:36 1999
+++ linux/net/decnet/dn_fib.c	Mon Jul  5 20:35:18 1999
@@ -23,7 +23,6 @@
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
-#include <linux/rtnetlink.h>
 #include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.9/linux/net/econet/econet.c linux/net/econet/econet.c
--- v2.3.9/linux/net/econet/econet.c	Sun Mar  7 15:25:23 1999
+++ linux/net/econet/econet.c	Sat Jul  3 17:57:22 1999
@@ -759,7 +759,8 @@
 		    (opt->station == station || opt->station == 0) &&
 		    (opt->net == net || opt->net == 0))
 			return sk;
-		sk = sk->sklist_next;
+
+		sk = sk->next;
 	}
 
 	return NULL;
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.9/linux/net/ipv4/af_inet.c	Wed Jun  9 14:45:36 1999
+++ linux/net/ipv4/af_inet.c	Sat Jul  3 17:57:22 1999
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.91 1999/06/09 08:28:55 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.93 1999/07/02 11:26:24 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -162,9 +162,6 @@
 
 static __inline__ void kill_sk_now(struct sock *sk)
 {
-	/* No longer exists. */
-	del_from_prot_sklist(sk);
-
 	/* Remove from protocol hash chains. */
 	sk->prot->unhash(sk);
 
@@ -239,7 +236,7 @@
 {
 	struct sock *sk=sock->sk;
 	if (sk->prot->setsockopt==NULL)
-		return(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	return sk->prot->setsockopt(sk,level,optname,optval,optlen);
 }
 
@@ -256,7 +253,7 @@
 {
 	struct sock *sk=sock->sk;
 	if (sk->prot->getsockopt==NULL)
-		return(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	return sk->prot->getsockopt(sk,level,optname,optval,optlen);
 }
 
@@ -268,12 +265,10 @@
 {
 	/* We may need to bind the socket. */
 	if (sk->num == 0) {
-		sk->num = sk->prot->good_socknum();
-		if (sk->num == 0) 
-			return(-EAGAIN);
+		if (sk->prot->get_port(sk, 0) != 0)
+			return -EAGAIN;
 		sk->sport = htons(sk->num);
 		sk->prot->hash(sk);
-		add_to_prot_sklist(sk);
 	}
 	return 0;
 }
@@ -293,29 +288,38 @@
 int inet_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
+	unsigned char old_state;
 
 	if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
-		return(-EINVAL);
-
-	if (inet_autobind(sk) != 0)
-		return -EAGAIN;
+		return -EINVAL;
 
-	/* We might as well re use these. */ 
 	if ((unsigned) backlog == 0)	/* BSDism */
 		backlog = 1;
 	if ((unsigned) backlog > SOMAXCONN)
 		backlog = SOMAXCONN;
 	sk->max_ack_backlog = backlog;
-	if (sk->state != TCP_LISTEN) {
-		sk->ack_backlog = 0;
+
+	/* Really, if the socket is already in listen state
+	 * we can only allow the backlog to be adjusted.
+	 */
+	old_state = sk->state;
+	if (old_state != TCP_LISTEN) {
 		sk->state = TCP_LISTEN;
+		sk->ack_backlog = 0;
+		if (sk->num == 0) {
+			if (sk->prot->get_port(sk, 0) != 0) {
+				sk->state = old_state;
+				return -EAGAIN;
+			}
+			sk->sport = htons(sk->num);
+		}
+
 		dst_release(xchg(&sk->dst_cache, NULL));
-		sk->prot->rehash(sk);
-		add_to_prot_sklist(sk);
+		sk->prot->hash(sk);
+		sk->socket->flags |= SO_ACCEPTCON;
 		sk->write_space = inet_listen_write_space;
 	}
-	sk->socket->flags |= SO_ACCEPTCON;
-	return(0);
+	return 0;
 }
 
 /*
@@ -427,7 +431,6 @@
 
 		/* Add to protocol hash chains. */
 		sk->prot->hash(sk);
-		add_to_prot_sklist(sk);
 	}
 
 	if (sk->prot->init) {
@@ -486,11 +489,9 @@
 		 */
 		timeout = 0;
 		if (sk->linger && !(current->flags & PF_EXITING)) {
-			timeout = MAX_SCHEDULE_TIMEOUT;
-
-			/* XXX This makes no sense whatsoever... -DaveM */
-			if (!sk->lingertime)
-				timeout = HZ*sk->lingertime;
+			timeout = HZ * sk->lingertime;
+			if (!timeout)
+				timeout = MAX_SCHEDULE_TIMEOUT;
 		}
 		sock->sk = NULL;
 		sk->socket = NULL;
@@ -543,21 +544,17 @@
 	if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END))
 		return -EADDRINUSE;
 #endif		 
-	if (snum == 0) 
-		snum = sk->prot->good_socknum();
-	if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
-		return(-EACCES);
+	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+		return -EACCES;
 	
 	/* Make sure we are allowed to bind here. */
-	if(sk->prot->verify_bind(sk, snum))
+	if (sk->prot->get_port(sk, snum) != 0)
 		return -EADDRINUSE;
 
-	sk->num = snum;
-	sk->sport = htons(snum);
+	sk->sport = htons(sk->num);
 	sk->daddr = 0;
 	sk->dport = 0;
-	sk->prot->rehash(sk);
-	add_to_prot_sklist(sk);
+	sk->prot->hash(sk);
 	dst_release(sk->dst_cache);
 	sk->dst_cache=NULL;
 	return(0);
@@ -570,12 +567,12 @@
 	int err;
 
 	if (inet_autobind(sk) != 0)
-		return(-EAGAIN);
+		return -EAGAIN;
 	if (sk->prot->connect == NULL) 
-		return(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	err = sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
 	if (err < 0) 
-		return(err);
+		return err;
 	return(0);
 }
 
@@ -626,18 +623,20 @@
 		if (flags & O_NONBLOCK)
 			return -EALREADY;
 	} else {
+		if (sk->prot->connect == NULL) 
+			return -EOPNOTSUPP;
+
 		/* We may need to bind the socket. */
 		if (inet_autobind(sk) != 0)
-			return(-EAGAIN);
-		if (sk->prot->connect == NULL) 
-			return(-EOPNOTSUPP);
+			return -EAGAIN;
+
 		err = sk->prot->connect(sk, uaddr, addr_len);
 		/* Note: there is a theoretical race here when an wake up
 		   occurred before inet_wait_for_connect is entered. In 2.3
 		   the wait queue setup should be moved before the low level
 		   connect call. -AK*/
 		if (err < 0)
-			return(err);
+			return err;
   		sock->state = SS_CONNECTING;
 	}
 	
@@ -645,7 +644,7 @@
 		goto sock_error;
 
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) 
-	  	return (-EINPROGRESS);
+	  	return -EINPROGRESS;
 
 	if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
 		inet_wait_for_connect(sk);
@@ -656,7 +655,7 @@
 	sock->state = SS_CONNECTED;
 	if ((sk->state != TCP_ESTABLISHED) && sk->err)
 		goto sock_error; 
-	return(0);
+	return 0;
 
 sock_error:	
 	/* This is ugly but needed to fix a race in the ICMP error handler */
@@ -750,7 +749,7 @@
 	sin->sin_family = AF_INET;
 	if (peer) {
 		if (!tcp_connected(sk->state)) 
-			return(-ENOTCONN);
+			return -ENOTCONN;
 		sin->sin_port = sk->dport;
 		sin->sin_addr.s_addr = sk->daddr;
 	} else {
@@ -774,12 +773,12 @@
 	int err;
 	
 	if (sock->flags & SO_ACCEPTCON)
-		return(-EINVAL);
+		return -EINVAL;
 	if (sk->prot->recvmsg == NULL) 
-		return(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	/* We may need to bind the socket. */
 	if (inet_autobind(sk) != 0)
-		return(-EAGAIN);
+		return -EAGAIN;
 	err = sk->prot->recvmsg(sk, msg, size, flags&MSG_DONTWAIT,
 				flags&~MSG_DONTWAIT, &addr_len);
 	if (err >= 0)
@@ -796,15 +795,15 @@
 	if (sk->shutdown & SEND_SHUTDOWN) {
 		if (!(msg->msg_flags&MSG_NOSIGNAL))
 			send_sig(SIGPIPE, current, 1);
-		return(-EPIPE);
+		return -EPIPE;
 	}
 	if (sk->prot->sendmsg == NULL) 
-		return(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	if(sk->err)
 		return sock_error(sk);
 
 	/* We may need to bind the socket. */
-	if(inet_autobind(sk) != 0)
+	if (inet_autobind(sk) != 0)
 		return -EAGAIN;
 
 	return sk->prot->sendmsg(sk, msg, size);
@@ -822,11 +821,13 @@
 		       1->2 bit 2 snds.
 		       2->3 */
 	if ((how & ~SHUTDOWN_MASK) || how==0)	/* MAXINT->0 */
-		return(-EINVAL);
+		return -EINVAL;
+	if (!sk)
+		return -ENOTCONN;
 	if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
 		sock->state = SS_CONNECTED;
-	if (!sk || !tcp_connected(sk->state)) 
-		return(-ENOTCONN);
+	if (!tcp_connected(sk->state)) 
+		return -ENOTCONN;
 	sk->shutdown |= how;
 	if (sk->prot->shutdown)
 		sk->prot->shutdown(sk, how);
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.3.9/linux/net/ipv4/icmp.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv4/icmp.c	Mon Jul  5 20:35:18 1999
@@ -269,7 +269,6 @@
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/raw.h>
-#include <net/snmp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.3.9/linux/net/ipv4/proc.c	Wed May 26 18:14:37 1999
+++ linux/net/ipv4/proc.c	Sat Jul  3 17:57:22 1999
@@ -7,7 +7,7 @@
  *		PROC file system.  It is mainly used for debugging and
  *		statistics.
  *
- * Version:	$Id: proc.c,v 1.35 1999/05/27 00:37:38 davem Exp $
+ * Version:	$Id: proc.c,v 1.36 1999/07/02 11:26:34 davem Exp $
  *
  * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -49,189 +49,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/raw.h>
-
-/* Format a single open_request into tmpbuf. */
-static inline void get__openreq(struct sock *sk, struct open_request *req, 
-				char *tmpbuf, 
-				int i)
-{
-	sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
-		i,
-		(long unsigned int)req->af.v4_req.loc_addr,
-		ntohs(sk->sport),
-		(long unsigned int)req->af.v4_req.rmt_addr,
-		ntohs(req->rmt_port),
-		TCP_SYN_RECV,
-		0,0, /* could print option size, but that is af dependent. */
-		1,   /* timers active (only the expire timer) */  
-		(unsigned long)(req->expires - jiffies), 
-		req->retrans,
-		sk->socket ? sk->socket->inode->i_uid : 0,
-		0,  /* non standard timer */  
-		0 /* open_requests have no inode */
-		); 
-}
-
-/* Format a single socket into tmpbuf. */
-static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
-{
-	unsigned long  dest, src;
-	unsigned short destp, srcp;
-	int timer_active, timer_active1, timer_active2;
-	int tw_bucket = 0;
-	unsigned long timer_expires;
-	struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
-
-	dest  = sp->daddr;
-	src   = sp->rcv_saddr;
-	destp = sp->dport;
-	srcp  = sp->sport;
-	
-	/* FIXME: The fact that retransmit_timer occurs as a field
-	 * in two different parts of the socket structure is,
-	 * to say the least, confusing. This code now uses the
-	 * right retransmit_timer variable, but I'm not sure
-	 * the rest of the timer stuff is still correct.
-	 * In particular I'm not sure what the timeout value
-	 * is suppose to reflect (as opposed to tm->when). -- erics
-	 */
-	
-	destp = ntohs(destp);
-	srcp  = ntohs(srcp);
-	if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
-		extern int tcp_tw_death_row_slot;
-		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
-		int slot_dist;
-
-		tw_bucket	= 1;
-		timer_active1	= timer_active2 = 0;
-		timer_active	= 3;
-		slot_dist	= tw->death_slot;
-		if(slot_dist > tcp_tw_death_row_slot)
-			slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
-		else
-			slot_dist = tcp_tw_death_row_slot - slot_dist;
-		timer_expires	= jiffies + (slot_dist * TCP_TWKILL_PERIOD);
-	} else {
-		timer_active1 = tp->retransmit_timer.prev != NULL;
-		timer_active2 = sp->timer.prev != NULL;
-		timer_active	= 0;
-		timer_expires	= (unsigned) -1;
-	}
-	if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
-		timer_active	= 1;
-		timer_expires	= tp->retransmit_timer.expires;
-	}
-	if (timer_active2 && sp->timer.expires < timer_expires) {
-		timer_active	= 2;
-		timer_expires	= sp->timer.expires;
-	}
-	if(timer_active == 0)
-		timer_expires = jiffies;
-	sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
-		i, src, srcp, dest, destp, sp->state, 
-		(tw_bucket ?
-		 0 :
-		 (format == 0) ?
-		 tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
-		(tw_bucket ?
-		 0 :
-		 (format == 0) ?
-		 tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
-		timer_active, timer_expires-jiffies,
-		(tw_bucket ? 0 : tp->retransmits),
-		(!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
-		(!tw_bucket && timer_active) ? sp->timeout : 0,
-		(!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
-}
-
-/*
- * Get__netinfo returns the length of that string.
- *
- * KNOWN BUGS
- *  As in get_unix_netinfo, the buffer might be too small. If this
- *  happens, get__netinfo returns only part of the available infos.
- *
- *  Assumes that buffer length is a multiply of 128 - if not it will
- *  write past the end.   
- */
-static int
-get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
-{
-	struct sock *sp, *next;
-	int len=0, i = 0;
-	off_t pos=0;
-	off_t begin;
-	char tmpbuf[129];
-  
-	if (offset < 128) 
-		len += sprintf(buffer, "%-127s\n",
-			       "  sl  local_address rem_address   st tx_queue "
-			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
-	pos = 128;
-	SOCKHASH_LOCK_READ();
-	sp = pro->sklist_next;
-	while(sp != (struct sock *)pro) {
-		if (format == 0 && sp->state == TCP_LISTEN) {
-			struct open_request *req;
-
-			for (req = sp->tp_pinfo.af_tcp.syn_wait_queue; req;
-			     i++, req = req->dl_next) {
-				if (req->sk)
-					continue;
-				pos += 128;
-				if (pos < offset) 
-					continue;
-				get__openreq(sp, req, tmpbuf, i); 
-				len += sprintf(buffer+len, "%-127s\n", tmpbuf);
-				if(len >= length) 
-					goto out;
-			}
-		}
-		
-		pos += 128;
-		if (pos < offset)
-			goto next;
-		
-		get__sock(sp, tmpbuf, i, format);
-		
-		len += sprintf(buffer+len, "%-127s\n", tmpbuf);
-		if(len >= length)
-			break;
-	next:
-		next = sp->sklist_next;
-		sp = next;
-		i++;
-	}
-out: 
-	SOCKHASH_UNLOCK_READ();
-	
-	begin = len - (pos - offset);
-	*start = buffer + begin;
-	len -= begin;
-	if(len>length)
-		len = length;
-	if (len<0)
-		len = 0; 
-	return len;
-} 
-
-int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-	return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
-}
-
-int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-	return get__netinfo(&udp_prot, buffer,1, start, offset, length);
-}
-
-int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-	return get__netinfo(&raw_prot, buffer,1, start, offset, length);
-}
 
 /*
  *	Report socket allocation statistics [mea@utu.fi]
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.3.9/linux/net/ipv4/raw.c	Mon May 31 22:07:43 1999
+++ linux/net/ipv4/raw.c	Sat Jul  3 17:57:23 1999
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.41 1999/05/30 01:16:19 davem Exp $
+ * Version:	$Id: raw.c,v 1.42 1999/07/02 11:26:26 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -70,60 +70,32 @@
 
 static void raw_v4_hash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
+	struct sock **skp = &raw_v4_htable[sk->num & (RAWV4_HTABLE_SIZE - 1)];
 
-	num &= (RAWV4_HTABLE_SIZE - 1);
-	skp = &raw_v4_htable[num];
 	SOCKHASH_LOCK_WRITE();
-	sk->next = *skp;
+	if ((sk->next = *skp) != NULL)
+		(*skp)->pprev = &sk->next;
 	*skp = sk;
-	sk->hashent = num;
+	sk->pprev = skp;
+	sk->prot->inuse++;
+	if(sk->prot->highestinuse < sk->prot->inuse)
+		sk->prot->highestinuse = sk->prot->inuse;
 	SOCKHASH_UNLOCK_WRITE();
 }
 
 static void raw_v4_unhash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
-
-	num &= (RAWV4_HTABLE_SIZE - 1);
-	skp = &raw_v4_htable[num];
-
 	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
+	if (sk->pprev) {
+		if (sk->next)
+			sk->next->pprev = sk->pprev;
+		*sk->pprev = sk->next;
+		sk->pprev = NULL;
+		sk->prot->inuse--;
 	}
 	SOCKHASH_UNLOCK_WRITE();
 }
 
-static void raw_v4_rehash(struct sock *sk)
-{
-	struct sock **skp;
-	int num = sk->num;
-	int oldnum = sk->hashent;
-
-	num &= (RAWV4_HTABLE_SIZE - 1);
-	skp = &raw_v4_htable[oldnum];
-
-	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
-	}
-	sk->next = raw_v4_htable[num];
-	raw_v4_htable[num] = sk;
-	sk->hashent = num;
-	SOCKHASH_UNLOCK_WRITE();
-}
-
 static __inline__ struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
 					       unsigned long raddr, unsigned long laddr,
 					       int dif)
@@ -640,9 +612,69 @@
 	return -ENOPROTOOPT;
 }
 
+static void get_raw_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	unsigned int dest, src;
+	__u16 destp, srcp;
+	int timer_active;
+	unsigned long timer_expires;
+
+	dest  = sp->daddr;
+	src   = sp->rcv_saddr;
+	destp = ntohs(sp->dport);
+	srcp  = ntohs(sp->sport);
+	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
+	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
+	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		i, src, srcp, dest, destp, sp->state, 
+		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
+		timer_active, timer_expires-jiffies, 0,
+		sp->socket->inode->i_uid, timer_active ? sp->timeout : 0,
+		sp->socket ? sp->socket->inode->i_ino : 0);
+}
+
+int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0, num = 0, i;
+	off_t pos = 0;
+	off_t begin;
+	char tmpbuf[129];
+
+	if (offset < 128) 
+		len += sprintf(buffer, "%-127s\n",
+			       "  sl  local_address rem_address   st tx_queue "
+			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
+	pos = 128;
+	SOCKHASH_LOCK_READ();
+	for (i = 0; i < RAWV4_HTABLE_SIZE; i++) {
+		struct sock *sk;
+
+		for (sk = raw_v4_htable[i]; sk; sk = sk->next, num++) {
+			if (sk->family != PF_INET)
+				continue;
+			pos += 128;
+			if (pos < offset)
+				continue;
+			get_raw_sock(sk, tmpbuf, i);
+			len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+out:
+	SOCKHASH_UNLOCK_READ();
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len > length)
+		len = length;
+	if (len < 0)
+		len = 0; 
+	return len;
+}
+
 struct proto raw_prot = {
-	(struct sock *)&raw_prot,	/* sklist_next */
-	(struct sock *)&raw_prot,	/* sklist_prev */
 	raw_close,			/* close */
 	udp_connect,			/* connect */
 	NULL,				/* accept */
@@ -666,9 +698,7 @@
 	raw_rcv_skb,			/* backlog_rcv */
 	raw_v4_hash,			/* hash */
 	raw_v4_unhash,			/* unhash */
-	raw_v4_rehash,			/* rehash */
-	NULL,				/* good_socknum */
-	NULL,				/* verify_bind */
+	NULL,				/* get_port */
 	128,				/* max_header */
 	0,				/* retransmits */
 	"RAW",				/* name */
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.9/linux/net/ipv4/tcp.c	Wed Jun 30 13:38:20 1999
+++ linux/net/ipv4/tcp.c	Mon Jul  5 20:22:09 1999
@@ -1339,7 +1339,7 @@
 		break;
 	}
 
-	if(copied > 0 && msg->msg_name)
+	if (copied > 0 && msg->msg_name)
 		tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
 					       msg->msg_name);       
 
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.9/linux/net/ipv4/tcp_input.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv4/tcp_input.c	Sat Jul  3 17:57:23 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.169 1999/06/09 08:29:13 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.170 1999/07/02 11:26:28 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -917,25 +917,26 @@
 /* Must be called only from BH context. */
 void tcp_timewait_kill(struct tcp_tw_bucket *tw)
 {
+	struct tcp_bind_bucket *tb = tw->tb;
+
 	SOCKHASH_LOCK_WRITE_BH();
 
-	/* Unlink from various places. */
+	/* Disassociate with bind bucket. */
 	if(tw->bind_next)
 		tw->bind_next->bind_pprev = tw->bind_pprev;
 	*(tw->bind_pprev) = tw->bind_next;
-	if(tw->tb->owners == NULL)
-		tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
+	if (tb->owners == NULL) {
+		if (tb->next)
+			tb->next->pprev = tb->pprev;
+		*(tb->pprev) = tb->next;
+		kmem_cache_free(tcp_bucket_cachep, tb);
+	}
 
+	/* Unlink from established hashes. */
 	if(tw->next)
 		tw->next->pprev = tw->pprev;
 	*tw->pprev = tw->next;
 
-	/* We decremented the prot->inuse count when we entered TIME_WAIT
-	 * and the sock from which this came was destroyed.
-	 */
-	tw->sklist_next->sklist_prev = tw->sklist_prev;
-	tw->sklist_prev->sklist_next = tw->sklist_next;
-
 	SOCKHASH_UNLOCK_WRITE_BH();
 
 	/* Ok, now free it up. */
@@ -1040,11 +1041,9 @@
 		sk->bind_next->bind_pprev = &tw->bind_next;
 	tw->bind_pprev = sk->bind_pprev;
 	*sk->bind_pprev = (struct sock *)tw;
+	sk->prev = NULL;
 
-	/* Step 3: Same for the protocol sklist. */
-	(tw->sklist_next = sk->sklist_next)->sklist_prev = (struct sock *)tw;
-	(tw->sklist_prev = sk->sklist_prev)->sklist_next = (struct sock *)tw;
-	sk->sklist_next = NULL;
+	/* Step 3: Un-charge protocol socket in-use count. */
 	sk->prot->inuse--;
 
 	/* Step 4: Hash TW into TIMEWAIT half of established hash table. */
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.9/linux/net/ipv4/tcp_ipv4.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv4/tcp_ipv4.c	Mon Jul  5 11:30:11 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.180 1999/06/09 08:29:19 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.182 1999/07/05 01:34:07 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -132,28 +132,9 @@
 	return tcp_hashfn(laddr, lport, faddr, fport);
 }
 
-/* Invariant, sk->num is non-zero. */
-void tcp_bucket_unlock(struct sock *sk)
-{
-	struct tcp_bind_bucket *tb;
-	unsigned short snum = sk->num;
-
-	SOCKHASH_LOCK_WRITE();
-	for(tb = tcp_bhash[tcp_bhashfn(snum)]; tb; tb = tb->next) {
-		if(tb->port == snum) {
-			if(tb->owners == NULL &&
-			   (tb->flags & TCPB_FLAG_LOCKED)) {
-				tb->flags &= ~(TCPB_FLAG_LOCKED |
-					       TCPB_FLAG_FASTREUSE);
-				tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
-			}
-			break;
-		}
-	}
-	SOCKHASH_UNLOCK_WRITE();
-}
-
-/* The sockhash lock must be held as a writer here. */
+/* Allocate and initialize a new TCP local port bind bucket.
+ * The sockhash lock must be held as a writer here.
+ */
 struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
 {
 	struct tcp_bind_bucket *tb;
@@ -163,7 +144,7 @@
 		struct tcp_bind_bucket **head =
 			&tcp_bhash[tcp_bhashfn(snum)];
 		tb->port = snum;
-		tb->flags = TCPB_FLAG_LOCKED;
+		tb->fastreuse = 0;
 		tb->owners = NULL;
 		if((tb->next = *head) != NULL)
 			tb->next->pprev = &tb->next;
@@ -186,133 +167,176 @@
 	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for( ; (tb && (tb->port != snum)); tb = tb->next)
 		;
-	if(tb == NULL && tcp_bucket_create(snum) == NULL)
-		ret = 1;
+	ret = 0;
+	if (tb == NULL) {
+		if ((tb = tcp_bucket_create(snum)) == NULL)
+			ret = 1;
+	}
 	SOCKHASH_UNLOCK_WRITE();
 
 	return ret;
 }
 #endif
 
-static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
+static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child)
+{
+	struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev;
+
+	if ((child->bind_next = tb->owners) != NULL)
+		tb->owners->bind_pprev = &child->bind_next;
+	tb->owners = child;
+	child->bind_pprev = &tb->owners;
+	child->prev = (struct sock *) tb;
+}
+
+__inline__ void tcp_inherit_port(struct sock *sk, struct sock *child)
+{
+	SOCKHASH_LOCK_WRITE();
+	__tcp_inherit_port(sk, child);
+	SOCKHASH_UNLOCK_WRITE();
+}
+
+/* Obtain a reference to a local port for the given sock,
+ * if snum is zero it means select any available local port.
+ */
+static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
 {
 	struct tcp_bind_bucket *tb;
-	int result = 0;
 
 	SOCKHASH_LOCK_WRITE();
-	for(tb = tcp_bhash[tcp_bhashfn(snum)];
-	    (tb && (tb->port != snum));
-	    tb = tb->next)
-		;
-	if(tb && tb->owners) {
-		/* Fast path for reuse ports, see include/net/tcp.h for a very
-		 * detailed description of why this works, and why it is worth
-		 * the effort at all. -DaveM
-		 */
-		if((tb->flags & TCPB_FLAG_FASTREUSE)	&&
-		   (sk->reuse != 0)) {
-			goto go_like_smoke;
+	if (snum == 0) {
+		int rover = tcp_port_rover;
+		int low = sysctl_local_port_range[0];
+		int high = sysctl_local_port_range[1];
+		int remaining = (high - low) + 1;
+
+		do {	rover++;
+			if ((rover < low) || (rover > high))
+				rover = low;
+			tb = tcp_bhash[tcp_bhashfn(rover)];
+			for ( ; tb; tb = tb->next)
+				if (tb->port == rover)
+					goto next;
+			break;
+		next:
+		} while (--remaining > 0);
+		tcp_port_rover = rover;
+
+		/* Exhausted local port range during search? */
+		if (remaining <= 0)
+			goto fail;
+
+		/* OK, here is the one we will use. */
+		snum = rover;
+		tb = NULL;
+	} else {
+		for (tb = tcp_bhash[tcp_bhashfn(snum)];
+		     tb != NULL;
+		     tb = tb->next)
+			if (tb->port == snum)
+				break;
+	}
+	if (tb != NULL && tb->owners != NULL) {
+		if (tb->fastreuse != 0 && sk->reuse != 0) {
+			goto success;
 		} else {
-			struct sock *sk2;
+			struct sock *sk2 = tb->owners;
 			int sk_reuse = sk->reuse;
 
-			/* We must walk the whole port owner list in this case. -DaveM */
-			for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) {
+			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
 				if (sk->bound_dev_if == sk2->bound_dev_if) {
-					if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) {
-						if(!sk2->rcv_saddr		||
-						   !sk->rcv_saddr		||
-						   (sk2->rcv_saddr == sk->rcv_saddr))
+					if (!sk_reuse	||
+					    !sk2->reuse	||
+					    sk2->state == TCP_LISTEN) {
+						if (!sk2->rcv_saddr	||
+						    !sk->rcv_saddr	||
+						    (sk2->rcv_saddr == sk->rcv_saddr))
 							break;
 					}
 				}
 			}
-			if(sk2 != NULL)
-				result = 1;
-		}
-	}
-	if(result == 0) {
-		if(tb == NULL) {
-			if((tb = tcp_bucket_create(snum)) == NULL)
-				result = 1;
-			else if (sk->reuse && sk->state != TCP_LISTEN)
-				tb->flags |= TCPB_FLAG_FASTREUSE;
-		} else {
-			/* It could be pending garbage collection, this
-			 * kills the race and prevents it from disappearing
-			 * out from under us by the time we use it.  -DaveM
-			 */
-			if(tb->owners == NULL) {
-				if (!(tb->flags & TCPB_FLAG_LOCKED)) {
-					tb->flags = (TCPB_FLAG_LOCKED |
-						     ((sk->reuse &&
-						       sk->state != TCP_LISTEN) ?
-						      TCPB_FLAG_FASTREUSE : 0));
-					tcp_dec_slow_timer(TCP_SLT_BUCKETGC);
-				} else if (!(tb->flags & TCPB_FLAG_GOODSOCKNUM)) {
-					/* Someone is in between the bind
-					 * and the actual connect or listen.
-					 * See if it was a legitimate reuse
-					 * and we are as well, else punt.
-					 */
-					if (sk->reuse == 0 ||
-					    !(tb->flags & TCPB_FLAG_FASTREUSE))
-						result = 1;
-				} else
-					tb->flags &= ~TCPB_FLAG_GOODSOCKNUM;
-			}
+			/* If we found a conflict, fail. */
+			if (sk2 != NULL)
+				goto fail;
 		}
 	}
-go_like_smoke:
+	if (tb == NULL &&
+	    (tb = tcp_bucket_create(snum)) == NULL)
+			goto fail;
+	if (tb->owners == NULL) {
+		if (sk->reuse && sk->state != TCP_LISTEN)
+			tb->fastreuse = 1;
+		else
+			tb->fastreuse = 0;
+	} else if (tb->fastreuse &&
+		   ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
+		tb->fastreuse = 0;
+success:
+	sk->num = snum;
+	if ((sk->bind_next = tb->owners) != NULL)
+		tb->owners->bind_pprev = &sk->bind_next;
+	tb->owners = sk;
+	sk->bind_pprev = &tb->owners;
+	sk->prev = (struct sock *) tb;
+
 	SOCKHASH_UNLOCK_WRITE();
-	return result;
+	return 0;
+
+fail:
+	SOCKHASH_UNLOCK_WRITE();
+	return 1;
 }
 
-unsigned short tcp_good_socknum(void)
+/* Get rid of any references to a local port held by the
+ * given sock.
+ */
+__inline__ void __tcp_put_port(struct sock *sk)
 {
 	struct tcp_bind_bucket *tb;
-	int low = sysctl_local_port_range[0];
-	int high = sysctl_local_port_range[1];
-	int remaining = (high - low) + 1;
-	int rover;
 
+	tb = (struct tcp_bind_bucket *) sk->prev;
+	if (sk->bind_next)
+		sk->bind_next->bind_pprev = sk->bind_pprev;
+	*(sk->bind_pprev) = sk->bind_next;
+	sk->prev = NULL;
+	if (tb->owners == NULL) {
+		if (tb->next)
+			tb->next->pprev = tb->pprev;
+		*(tb->pprev) = tb->next;
+		kmem_cache_free(tcp_bucket_cachep, tb);
+	}
+}
+
+void tcp_put_port(struct sock *sk)
+{
 	SOCKHASH_LOCK_WRITE();
-	rover = tcp_port_rover;
-	do {
-		rover += 1;
-		if((rover < low) || (rover > high))
-			rover = low;
-		tb = tcp_bhash[tcp_bhashfn(rover)];
-		for( ; tb; tb = tb->next) {
-			if(tb->port == rover)
-				goto next;
-		}
-		break;
-	next:
-	} while(--remaining > 0);
-	tcp_port_rover = rover;
-	tb = NULL;
-	if((remaining <= 0) || ((tb = tcp_bucket_create(rover)) == NULL))
-		rover = 0;
-	if (tb != NULL)
-		tb->flags |= TCPB_FLAG_GOODSOCKNUM;
+	__tcp_put_port(sk);
 	SOCKHASH_UNLOCK_WRITE();
+}
+
+static __inline__ void __tcp_v4_hash(struct sock *sk)
+{
+	struct sock **skp;
+
+	if(sk->state == TCP_LISTEN)
+		skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+	else
+		skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
-	return rover;
+	if((sk->next = *skp) != NULL)
+		(*skp)->pprev = &sk->next;
+	*skp = sk;
+	sk->pprev = skp;
+	sk->prot->inuse++;
+	if(sk->prot->highestinuse < sk->prot->inuse)
+		sk->prot->highestinuse = sk->prot->inuse;
 }
 
 static void tcp_v4_hash(struct sock *sk)
 {
 	if (sk->state != TCP_CLOSE) {
-		struct sock **skp;
-
 		SOCKHASH_LOCK_WRITE();
-		skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
-		if((sk->next = *skp) != NULL)
-			(*skp)->pprev = &sk->next;
-		*skp = sk;
-		sk->pprev = skp;
-		tcp_sk_bindify(sk);
+		__tcp_v4_hash(sk);
 		SOCKHASH_UNLOCK_WRITE();
 	}
 }
@@ -325,39 +349,9 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
+		sk->prot->inuse--;
 		tcp_reg_zap(sk);
-		tcp_sk_unbindify(sk);
-	}
-	SOCKHASH_UNLOCK_WRITE();
-}
-
-static void tcp_v4_rehash(struct sock *sk)
-{
-	unsigned char state;
-
-	SOCKHASH_LOCK_WRITE();
-	state = sk->state;
-	if(sk->pprev != NULL) {
-		if(sk->next)
-			sk->next->pprev = sk->pprev;
-		*sk->pprev = sk->next;
-		sk->pprev = NULL;
-		tcp_reg_zap(sk);
-	}
-	if(state != TCP_CLOSE) {
-		struct sock **skp;
-
-		if(state == TCP_LISTEN)
-			skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
-		else
-			skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
-
-		if((sk->next = *skp) != NULL)
-			(*skp)->pprev = &sk->next;
-		*skp = sk;
-		sk->pprev = skp;
-		if(state == TCP_LISTEN)
-			tcp_sk_bindify(sk);
+		__tcp_put_port(sk);
 	}
 	SOCKHASH_UNLOCK_WRITE();
 }
@@ -1344,7 +1338,6 @@
 #endif
 
 		memcpy(newsk, sk, sizeof(*newsk));
-		newsk->sklist_next = NULL;
 		newsk->state = TCP_SYN_RECV;
 
 		/* Clone the TCP header template */
@@ -1536,8 +1529,11 @@
 	if (newsk->sndbuf < (3 * newtp->pmtu_cookie))
 		newsk->sndbuf = min ((3 * newtp->pmtu_cookie), sysctl_wmem_max);
  
-	tcp_v4_hash(newsk);
-	add_to_prot_sklist(newsk);
+	SOCKHASH_LOCK_WRITE();
+	__tcp_v4_hash(newsk);
+	__tcp_inherit_port(sk, newsk);
+	SOCKHASH_UNLOCK_WRITE();
+
 	sk->data_ready(sk, 0); /* Deliver SIGIO */ 
 
 	return newsk;
@@ -1780,6 +1776,25 @@
 	goto discard_it;
 }
 
+static void __tcp_v4_rehash(struct sock *sk)
+{
+	struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
+
+	SOCKHASH_LOCK_WRITE();
+	if(sk->pprev) {
+		if(sk->next)
+			sk->next->pprev = sk->pprev;
+		*sk->pprev = sk->next;
+		sk->pprev = NULL;
+		tcp_reg_zap(sk);
+	}
+	if((sk->next = *skp) != NULL)
+		(*skp)->pprev = &sk->next;
+	*skp = sk;
+	sk->pprev = skp;
+	SOCKHASH_UNLOCK_WRITE();
+}
+
 int tcp_v4_rebuild_header(struct sock *sk)
 {
 	struct rtable *rt = (struct rtable *)sk->dst_cache;
@@ -1853,7 +1868,12 @@
 
 		sk->saddr = new_saddr;
 		sk->rcv_saddr = new_saddr;
-		tcp_v4_rehash(sk);
+
+		/* XXX The only one ugly spot where we need to
+		 * XXX really change the sockets identity after
+		 * XXX it has entered the hashes. -DaveM
+		 */
+		__tcp_v4_rehash(sk);
 	} 
         
 	return 0;
@@ -1948,20 +1968,192 @@
   	while((skb = __skb_dequeue(&tp->out_of_order_queue)) != NULL)
 		kfree_skb(skb);
 
-	/* Clean up a locked TCP bind bucket, this only happens if a
+	/* Clean up a referenced TCP bind bucket, this only happens if a
 	 * port is allocated for a socket, but it never fully connects.
-	 * In which case we will find num to be non-zero and daddr to
-	 * be zero.
 	 */
-	if(sk->daddr == 0 && sk->num != 0)
-		tcp_bucket_unlock(sk);
+	if(sk->prev != NULL)
+		tcp_put_port(sk);
 
 	return 0;
 }
 
+/* Proc filesystem TCP sock list dumping. */
+static void get_openreq(struct sock *sk, struct open_request *req, char *tmpbuf, int i)
+{
+	sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
+		i,
+		(long unsigned int)req->af.v4_req.loc_addr,
+		ntohs(sk->sport),
+		(long unsigned int)req->af.v4_req.rmt_addr,
+		ntohs(req->rmt_port),
+		TCP_SYN_RECV,
+		0,0, /* could print option size, but that is af dependent. */
+		1,   /* timers active (only the expire timer) */  
+		(unsigned long)(req->expires - jiffies), 
+		req->retrans,
+		sk->socket ? sk->socket->inode->i_uid : 0,
+		0,  /* non standard timer */  
+		0 /* open_requests have no inode */
+		); 
+}
+
+static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	unsigned int dest, src;
+	__u16 destp, srcp;
+	int timer_active, timer_active1, timer_active2;
+	unsigned long timer_expires;
+	struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
+
+	dest  = sp->daddr;
+	src   = sp->rcv_saddr;
+	destp = ntohs(sp->dport);
+	srcp  = ntohs(sp->sport);
+	timer_active1 = tp->retransmit_timer.prev != NULL;
+	timer_active2 = sp->timer.prev != NULL;
+	timer_active	= 0;
+	timer_expires	= (unsigned) -1;
+	if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
+		timer_active	= 1;
+		timer_expires	= tp->retransmit_timer.expires;
+	}
+	if (timer_active2 && sp->timer.expires < timer_expires) {
+		timer_active	= 2;
+		timer_expires	= sp->timer.expires;
+	}
+	if(timer_active == 0)
+		timer_expires = jiffies;
+
+	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		i, src, srcp, dest, destp, sp->state, 
+		tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
+		timer_active, timer_expires-jiffies,
+		tp->retransmits,
+		sp->socket ? sp->socket->inode->i_uid : 0,
+		timer_active ? sp->timeout : 0,
+		sp->socket ? sp->socket->inode->i_ino : 0);
+}
+
+static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
+{
+	extern int tcp_tw_death_row_slot;
+	unsigned int dest, src;
+	__u16 destp, srcp;
+	int slot_dist;
+
+	dest  = tw->daddr;
+	src   = tw->rcv_saddr;
+	destp = ntohs(tw->dport);
+	srcp  = ntohs(tw->sport);
+
+	slot_dist = tw->death_slot;
+	if(slot_dist > tcp_tw_death_row_slot)
+		slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
+	else
+		slot_dist = tcp_tw_death_row_slot - slot_dist;
+
+	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08X %08X %5d %8d %d",
+		i, src, srcp, dest, destp, TCP_TIME_WAIT, 0, 0,
+		3, slot_dist * TCP_TWKILL_PERIOD, 0, 0, 0, 0);
+}
+
+int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0, num = 0, i;
+	off_t begin, pos = 0;
+	char tmpbuf[129];
+
+	if (offset < 128)
+		len += sprintf(buffer, "%-127s\n",
+			       "  sl  local_address rem_address   st tx_queue "
+			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
+
+	pos = 128;
+	SOCKHASH_LOCK_READ();
+
+	/* First, walk listening socket table. */
+	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
+		struct sock *sk = tcp_listening_hash[i];
+
+		for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) {
+			struct open_request *req;
+			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+			if (sk->family != PF_INET)
+				continue;
+			pos += 128;
+			if (pos >= offset) {
+				get_tcp_sock(sk, tmpbuf, num);
+				len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+				if (len >= length)
+					goto out;
+			}
+			for (req = tp->syn_wait_queue; req; req = req->dl_next, num++) {
+				if (req->sk)
+					continue;
+				pos += 128;
+				if (pos < offset)
+					continue;
+				get_openreq(sk, req, tmpbuf, num);
+				len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+				if(len >= length) 
+					goto out;
+			}
+		}
+	}
+
+	/* Next, walk established hash chain. */
+	for (i = 0; i < (tcp_ehash_size >> 1); i++) {
+		struct sock *sk;
+
+		for(sk = tcp_ehash[i]; sk; sk = sk->next, num++) {
+			if (sk->family != PF_INET)
+				continue;
+			pos += 128;
+			if (pos < offset)
+				continue;
+			get_tcp_sock(sk, tmpbuf, num);
+			len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+
+	/* Finally, walk time wait buckets. */
+	for (i = (tcp_ehash_size>>1); i < tcp_ehash_size; i++) {
+		struct tcp_tw_bucket *tw;
+		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i];
+		     tw != NULL;
+		     tw = (struct tcp_tw_bucket *)tw->next, num++) {
+			if (tw->family != PF_INET)
+				continue;
+			pos += 128;
+			if (pos < offset)
+				continue;
+			get_timewait_sock(tw, tmpbuf, num);
+			len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+
+out:
+	SOCKHASH_UNLOCK_READ();
+
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len > length)
+		len = length;
+	if (len < 0)
+		len = 0; 
+	return len;
+}
+
 struct proto tcp_prot = {
-	(struct sock *)&tcp_prot,	/* sklist_next */
-	(struct sock *)&tcp_prot,	/* sklist_prev */
 	tcp_close,			/* close */
 	tcp_v4_connect,			/* connect */
 	tcp_accept,			/* accept */
@@ -1981,9 +2173,7 @@
 	tcp_v4_do_rcv,			/* backlog_rcv */
 	tcp_v4_hash,			/* hash */
 	tcp_v4_unhash,			/* unhash */
-	tcp_v4_rehash,			/* rehash */
-	tcp_good_socknum,		/* good_socknum */
-	tcp_v4_verify_bind,		/* verify_bind */
+	tcp_v4_get_port,		/* get_port */
 	128,				/* max_header */
 	0,				/* retransmits */
 	"TCP",				/* name */
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.3.9/linux/net/ipv4/tcp_timer.c	Wed May 26 18:14:38 1999
+++ linux/net/ipv4/tcp_timer.c	Sat Jul  3 17:57:23 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.64 1999/05/27 00:37:31 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.65 1999/07/02 11:26:35 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -31,7 +31,6 @@
 static void tcp_sltimer_handler(unsigned long);
 static void tcp_syn_recv_timer(unsigned long);
 static void tcp_keepalive(unsigned long data);
-static void tcp_bucketgc(unsigned long);
 static void tcp_twkill(unsigned long);
 
 struct timer_list	tcp_slow_timer = {
@@ -44,8 +43,7 @@
 struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = {
 	{ATOMIC_INIT(0), TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK	*/
 	{ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive},  /* KEEPALIVE	*/
-	{ATOMIC_INIT(0), TCP_TWKILL_PERIOD, 0, tcp_twkill},        /* TWKILL	*/
-	{ATOMIC_INIT(0), TCP_BUCKETGC_PERIOD, 0, tcp_bucketgc}     /* BUCKETGC	*/
+	{ATOMIC_INIT(0), TCP_TWKILL_PERIOD, 0, tcp_twkill}         /* TWKILL	*/
 };
 
 const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
@@ -250,43 +248,6 @@
 		}
 	}
 	return res;
-}
-
-/* Garbage collect TCP bind buckets. */
-static void tcp_bucketgc(unsigned long data)
-{
-	int i, reaped = 0;;
-
-	SOCKHASH_LOCK_WRITE_BH();
-	for(i = 0; i < tcp_bhash_size; i++) {
-		struct tcp_bind_bucket *tb = tcp_bhash[i];
-
-		while(tb) {
-			struct tcp_bind_bucket *next = tb->next;
-
-			if((tb->owners == NULL) &&
-			   !(tb->flags & TCPB_FLAG_LOCKED)) {
-				reaped++;
-
-				/* Unlink bucket. */
-				if(tb->next)
-					tb->next->pprev = tb->pprev;
-				*tb->pprev = tb->next;
-
-				/* Finally, free it up. */
-				kmem_cache_free(tcp_bucket_cachep, tb);
-			}
-			tb = next;
-		}
-	}
-	SOCKHASH_UNLOCK_WRITE_BH();
-
-	if(reaped != 0) {
-		struct tcp_sl_timer *slt = (struct tcp_sl_timer *)data;
-
-		/* Eat timer references. */
-		atomic_sub(reaped, &slt->count);
-	}
 }
 
 /* Kill off TIME_WAIT sockets once their lifetime has expired. */
diff -u --recursive --new-file v2.3.9/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.3.9/linux/net/ipv4/udp.c	Wed Jun 30 13:38:20 1999
+++ linux/net/ipv4/udp.c	Mon Jul  5 20:22:59 1999
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.70 1999/06/13 05:55:16 davem Exp $
+ * Version:	$Id: udp.c,v 1.71 1999/07/02 11:26:33 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -123,164 +123,102 @@
 
 struct sock *udp_hash[UDP_HTABLE_SIZE];
 
-static int udp_v4_verify_bind(struct sock *sk, unsigned short snum)
-{
-	struct sock *sk2;
-	int retval = 0, sk_reuse = sk->reuse;
-
-	SOCKHASH_LOCK_READ();
-	for(sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; sk2 = sk2->next) {
-		if((sk2->num == snum) && (sk2 != sk)) {
-			unsigned char state = sk2->state;
-			int sk2_reuse = sk2->reuse;
-
-			/* Two sockets can be bound to the same port if they're
-			 * bound to different interfaces.
-			 */
+/* Shared by v4/v6 udp. */
+int udp_port_rover = 0;
 
-			if(sk2->bound_dev_if != sk->bound_dev_if)
-				continue;
+static int udp_v4_get_port(struct sock *sk, unsigned short snum)
+{
+	SOCKHASH_LOCK_WRITE();
+	if (snum == 0) {
+		int best_size_so_far, best, result, i;
 
-			if(!sk2->rcv_saddr || !sk->rcv_saddr) {
-				if((!sk2_reuse)			||
-				   (!sk_reuse)			||
-				   (state == TCP_LISTEN)) {
-					retval = 1;
-					break;
-				}
-			} else if(sk2->rcv_saddr == sk->rcv_saddr) {
-				if((!sk_reuse)			||
-				   (!sk2_reuse)			||
-				   (state == TCP_LISTEN)) {
-					retval = 1;
-					break;
-				}
+		if (udp_port_rover > sysctl_local_port_range[1] ||
+		    udp_port_rover < sysctl_local_port_range[0])
+			udp_port_rover = sysctl_local_port_range[0];
+		best_size_so_far = 32767;
+		best = result = udp_port_rover;
+		for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+			struct sock *sk;
+			int size;
+
+			sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+			if (!sk) {
+				if (result > sysctl_local_port_range[1])
+					result = sysctl_local_port_range[0] +
+						((result - sysctl_local_port_range[0]) &
+						 (UDP_HTABLE_SIZE - 1));
+				goto gotit;
 			}
+			size = 0;
+			do {
+				if (++size >= best_size_so_far)
+					goto next;
+			} while ((sk = sk->next) != NULL);
+			best_size_so_far = size;
+			best = result;
+		next:
 		}
-	}
-	SOCKHASH_UNLOCK_READ();
-	return retval;
-}
-
-static inline int udp_lport_inuse(u16 num)
-{
-	struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)];
+		result = best;
+		for(;; result += UDP_HTABLE_SIZE) {
+			if (result > sysctl_local_port_range[1])
+				result = sysctl_local_port_range[0]
+					+ ((result - sysctl_local_port_range[0]) &
+					   (UDP_HTABLE_SIZE - 1));
+			if (!udp_lport_inuse(result))
+				break;
+		}
+gotit:
+		udp_port_rover = snum = result;
+	} else {
+		struct sock *sk2;
 
-	for(; sk != NULL; sk = sk->next) {
-		if(sk->num == num)
-			return 1;
+		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
+		     sk2 != NULL;
+		     sk2 = sk2->next) {
+			if (sk2->num == snum &&
+			    sk2 != sk &&
+			    sk2->bound_dev_if == sk->bound_dev_if &&
+			    (!sk2->rcv_saddr ||
+			     !sk->rcv_saddr ||
+			     sk2->rcv_saddr == sk->rcv_saddr) &&
+			    (!sk2->reuse || !sk->reuse))
+				goto fail;
+		}
 	}
+	sk->num = snum;
+	SOCKHASH_UNLOCK_WRITE();
 	return 0;
-}
-
-/* Shared by v4/v6 udp. */
-unsigned short udp_good_socknum(void)
-{
-	int result;
-	static int start = 0;
-	int i, best, best_size_so_far;
-
-	SOCKHASH_LOCK_READ();
-        if (start > sysctl_local_port_range[1] || start < sysctl_local_port_range[0])
-                start = sysctl_local_port_range[0];
-
-	best_size_so_far = 32767;	/* "big" num */
-        best = result = start;
-
-        for(i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
-		struct sock *sk;
-		int size;
 
-		sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
-
-                if(!sk) {
-                        if (result > sysctl_local_port_range[1])
-                                result = sysctl_local_port_range[0]
-                                        + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1));
-			goto out;
-                }
-
-		/* Is this one better than our best so far? */
-		size = 0;
-		do {
-			if(++size >= best_size_so_far)
-				goto next;
-		} while((sk = sk->next) != NULL);
-		best_size_so_far = size;
-		best = result;
-        next:
-	}
-
-	result = best;
-
-        for(;; result += UDP_HTABLE_SIZE) {
-                /* Get into range (but preserve hash bin)... */
-                if (result > sysctl_local_port_range[1])
-                        result = sysctl_local_port_range[0]
-                                + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1));
-                if (!udp_lport_inuse(result))
-                        break;
-        }
-out:
-	start = result;
-	SOCKHASH_UNLOCK_READ();
-	return result;
+fail:
+	SOCKHASH_UNLOCK_WRITE();
+	return 1;
 }
 
 static void udp_v4_hash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
-
-	num &= (UDP_HTABLE_SIZE - 1);
-	skp = &udp_hash[num];
+	struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)];
 
 	SOCKHASH_LOCK_WRITE();
-	sk->next = *skp;
+	if ((sk->next = *skp) != NULL)
+		(*skp)->pprev = &sk->next;
 	*skp = sk;
-	sk->hashent = num;
+	sk->pprev = skp;
+	sk->prot->inuse++;
+	if(sk->prot->highestinuse < sk->prot->inuse)
+		sk->prot->highestinuse = sk->prot->inuse;
 	SOCKHASH_UNLOCK_WRITE();
 }
 
 static void udp_v4_unhash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
-
-	num &= (UDP_HTABLE_SIZE - 1);
-	skp = &udp_hash[num];
-
-	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
-	}
-	SOCKHASH_UNLOCK_WRITE();
-}
-
-static void udp_v4_rehash(struct sock *sk)
-{
-	struct sock **skp;
-	int num = sk->num;
-	int oldnum = sk->hashent;
-
-	num &= (UDP_HTABLE_SIZE - 1);
-	skp = &udp_hash[oldnum];
-
 	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
+	if (sk->pprev) {
+		if (sk->next)
+			sk->next->pprev = sk->pprev;
+		*sk->pprev = sk->next;
+		sk->pprev = NULL;
+		sk->prot->inuse--;
 	}
-	sk->next = udp_hash[num];
-	udp_hash[num] = sk;
-	sk->hashent = num;
 	SOCKHASH_UNLOCK_WRITE();
 }
 
@@ -653,7 +591,7 @@
 	if (msg->msg_name) {
 		struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
 		if (msg->msg_namelen < sizeof(*usin))
-			return(-EINVAL);
+			return -EINVAL;
 		if (usin->sin_family != AF_INET)
 			return -EINVAL;
 
@@ -788,7 +726,6 @@
 		{
 			unsigned long amount;
 
-			if (sk->state == TCP_LISTEN) return(-EINVAL);
 			amount = sock_wspace(sk);
 			return put_user(amount, (int *)arg);
 		}
@@ -798,8 +735,6 @@
 			struct sk_buff *skb;
 			unsigned long amount;
 
-			if (sk->state == TCP_LISTEN)
-				return(-EINVAL);
 			amount = 0;
 			/* N.B. Is this interrupt safe??
 			   -> Yes. Interrupts do not remove skbs. --ANK (980725)
@@ -817,7 +752,7 @@
 		}
 
 		default:
-			return(-ENOIOCTLCMD);
+			return -ENOIOCTLCMD;
 	}
 	return(0);
 }
@@ -841,8 +776,8 @@
 	/*
 	 *	Check any passed addresses
 	 */
-  	if (addr_len) 
-  		*addr_len=sizeof(*sin);
+	if (addr_len)
+		*addr_len=sizeof(*sin);
 
 	if (flags & MSG_ERRQUEUE)
 		return ip_recv_error(sk, msg, len);
@@ -945,7 +880,7 @@
 
 	
 	if (addr_len < sizeof(*usin)) 
-	  	return(-EINVAL);
+	  	return -EINVAL;
 
 	/*
 	 *	1003.1g - break association.
@@ -961,7 +896,7 @@
 	}
 
 	if (usin->sin_family && usin->sin_family != AF_INET) 
-	  	return(-EAFNOSUPPORT);
+	  	return -EAFNOSUPPORT;
 
 	dst_release(xchg(&sk->dst_cache, NULL));
 
@@ -1226,9 +1161,69 @@
 	return(0);
 }
 
+static void get_udp_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	unsigned int dest, src;
+	__u16 destp, srcp;
+	int timer_active;
+	unsigned long timer_expires;
+
+	dest  = sp->daddr;
+	src   = sp->rcv_saddr;
+	destp = ntohs(sp->dport);
+	srcp  = ntohs(sp->sport);
+	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
+	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
+	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		i, src, srcp, dest, destp, sp->state, 
+		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
+		timer_active, timer_expires-jiffies, 0,
+		sp->socket->inode->i_uid, timer_active ? sp->timeout : 0,
+		sp->socket ? sp->socket->inode->i_ino : 0);
+}
+
+int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0, num = 0, i;
+	off_t pos = 0;
+	off_t begin;
+	char tmpbuf[129];
+
+	if (offset < 128) 
+		len += sprintf(buffer, "%-127s\n",
+			       "  sl  local_address rem_address   st tx_queue "
+			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
+	pos = 128;
+	SOCKHASH_LOCK_READ();
+	for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+		struct sock *sk;
+
+		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
+			if (sk->family != PF_INET)
+				continue;
+			pos += 128;
+			if (pos < offset)
+				continue;
+			get_udp_sock(sk, tmpbuf, i);
+			len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+out:
+	SOCKHASH_UNLOCK_READ();
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len > length)
+		len = length;
+	if (len < 0)
+		len = 0; 
+	return len;
+}
+
 struct proto udp_prot = {
-	(struct sock *)&udp_prot,	/* sklist_next */
-	(struct sock *)&udp_prot,	/* sklist_prev */
 	udp_close,			/* close */
 	udp_connect,			/* connect */
 	NULL,				/* accept */
@@ -1248,9 +1243,7 @@
 	udp_queue_rcv_skb,		/* backlog_rcv */
 	udp_v4_hash,			/* hash */
 	udp_v4_unhash,			/* unhash */
-	udp_v4_rehash,			/* rehash */
-	udp_good_socknum,		/* good_socknum */
-	udp_v4_verify_bind,		/* verify_bind */
+	udp_v4_get_port,		/* good_socknum */
 	128,				/* max_header */
 	0,				/* retransmits */
  	"UDP",				/* name */
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.3.9/linux/net/ipv6/af_inet6.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv6/af_inet6.c	Sat Jul  3 17:57:23 1999
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.44 1999/06/09 08:29:29 davem Exp $
+ *	$Id: af_inet6.c,v 1.45 1999/07/02 11:26:38 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -157,7 +157,6 @@
 		 */
 		sk->sport = ntohs(sk->num);
 		sk->prot->hash(sk);
-		add_to_prot_sklist(sk);
 	}
 
 	if (sk->prot->init) {
@@ -205,13 +204,13 @@
 		
 	addr_type = ipv6_addr_type(&addr->sin6_addr);
 	if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM)
-		return(-EINVAL);
+		return -EINVAL;
 
 	/* Check if the address belongs to the host. */
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		v4addr = addr->sin6_addr.s6_addr32[3];
 		if (inet_addr_type(v4addr) != RTN_LOCAL)
-			return(-EADDRNOTAVAIL);
+			return -EADDRNOTAVAIL;
 	} else {
 		if (addr_type != IPV6_ADDR_ANY) {
 			/* ipv4 addr of the socket is invalid.  Only the
@@ -220,7 +219,7 @@
 			v4addr = LOOPBACK4_IPV6;
 			if (!(addr_type & IPV6_ADDR_MULTICAST))	{
 				if (ipv6_chk_addr(&addr->sin6_addr, NULL, 0) == NULL)
-					return(-EADDRNOTAVAIL);
+					return -EADDRNOTAVAIL;
 			}
 		}
 	}
@@ -236,21 +235,17 @@
 		       sizeof(struct in6_addr));
 
 	snum = ntohs(addr->sin6_port);
-	if (snum == 0) 
-		snum = sk->prot->good_socknum();
-	if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
-		return(-EACCES);
+	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+		return -EACCES;
 
 	/* Make sure we are allowed to bind here. */
-	if(sk->prot->verify_bind(sk, snum))
+	if(sk->prot->get_port(sk, snum) != 0)
 		return -EADDRINUSE;
 
-	sk->num = snum;
 	sk->sport = ntohs(sk->num);
 	sk->dport = 0;
 	sk->daddr = 0;
-	sk->prot->rehash(sk);
-	add_to_prot_sklist(sk);
+	sk->prot->hash(sk);
 
 	return(0);
 }
@@ -318,7 +313,7 @@
 	sk = sock->sk;
 	if (peer) {
 		if (!tcp_connected(sk->state))
-			return(-ENOTCONN);
+			return -ENOTCONN;
 		sin->sin6_port = sk->dport;
 		memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.daddr,
 		       sizeof(struct in6_addr));
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c
--- v2.3.9/linux/net/ipv6/ip6_fw.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv6/ip6_fw.c	Mon Jul  5 20:03:14 1999
@@ -92,12 +92,11 @@
 	struct ip6_fw_rule *rl;
 
 	rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
-
-	memset(rl, 0, sizeof(struct ip6_fw_rule));
-
 	if (rl)
+	{
+		memset(rl, 0, sizeof(struct ip6_fw_rule));
 		rl->flowr.ops = &ip6_fw_ops;
-
+	}
 	return rl;
 }
 
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/proc.c linux/net/ipv6/proc.c
--- v2.3.9/linux/net/ipv6/proc.c	Wed May 26 18:14:38 1999
+++ linux/net/ipv6/proc.c	Sat Jul  3 17:57:23 1999
@@ -7,7 +7,7 @@
  *		PROC file system.  This is very similar to the IPv4 version,
  *		except it reports the sockets in the INET6 address family.
  *
- * Version:	$Id: proc.c,v 1.10 1999/05/27 00:38:14 davem Exp $
+ * Version:	$Id: proc.c,v 1.11 1999/07/02 11:26:45 davem Exp $
  *
  * Authors:	David S. Miller (davem@caip.rutgers.edu)
  *
@@ -25,140 +25,6 @@
 #include <net/tcp.h>
 #include <net/transp_v6.h>
 #include <net/ipv6.h>
-
-/* This is the main implementation workhorse of all these routines. */
-static int get__netinfo6(struct proto *pro, char *buffer, int format, char **start,
-			 off_t offset, int length)
-{
-	struct sock *sp;
-	struct tcp_opt *tp;
-	int timer_active, timer_active1, timer_active2;
-	unsigned long timer_expires;
-	struct in6_addr *dest, *src;
-	unsigned short destp, srcp;
-	int len = 0, i = 0;
-	off_t pos = 0;
-	off_t begin;
-	char tmpbuf[150];
-
-	if(offset < 149)
-		len += sprintf(buffer, "%-148s\n",
-			       "  sl  "						/* 6 */
-			       "local_address                         "		/* 38 */
-			       "remote_address                        "		/* 38 */
-			       "st tx_queue rx_queue tr tm->when retrnsmt"	/* 41 */
-			       "   uid  timeout inode");			/* 21 */
-										/*----*/
-										/*144 */
-
-	pos = 149;
-	SOCKHASH_LOCK_READ();
-	sp = pro->sklist_next;
-	while(sp != (struct sock *)pro) {
-		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
-		int tw_bucket = 0;
-
-		pos += 149;
-		if(pos < offset)
-			goto next;
-		tp = &(sp->tp_pinfo.af_tcp);
-		if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
-			tw_bucket = 1;
-			dest  = &tw->v6_daddr;
-			src   = &tw->v6_rcv_saddr;
-		} else {
-			dest  = &sp->net_pinfo.af_inet6.daddr;
-			src   = &sp->net_pinfo.af_inet6.rcv_saddr;
-		}
-		destp = ntohs(sp->dport);
-		srcp  = ntohs(sp->sport);
-
-		if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
-			extern int tcp_tw_death_row_slot;
-			int slot_dist;
-
-			timer_active1	= timer_active2 = 0;
-			timer_active	= 3;
-			slot_dist	= tw->death_slot;
-			if(slot_dist > tcp_tw_death_row_slot)
-				slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
-			else
-				slot_dist = tcp_tw_death_row_slot - slot_dist;
-			timer_expires	= jiffies + (slot_dist * TCP_TWKILL_PERIOD);
-		} else {
-			timer_active1 = tp->retransmit_timer.prev != NULL;
-			timer_active2 = sp->timer.prev != NULL;
-			timer_active = 0;
-			timer_expires = (unsigned) -1;
-		}
-		if(timer_active1 && tp->retransmit_timer.expires < timer_expires) {
-			timer_active = timer_active1;
-			timer_expires = tp->retransmit_timer.expires;
-		}
-		if(timer_active2 && sp->timer.expires < timer_expires) {
-			timer_active = timer_active2;
-			timer_expires = sp->timer.expires;
-		}
-		if(timer_active == 0)
-			timer_expires = jiffies;
-		sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-			"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
-			i,
-			src->s6_addr32[0], src->s6_addr32[1],
-			src->s6_addr32[2], src->s6_addr32[3], srcp,
-			dest->s6_addr32[0], dest->s6_addr32[1],
-			dest->s6_addr32[2], dest->s6_addr32[3], destp,
-			sp->state,
-			(tw_bucket ?
-			 0 :
-			 (format == 0) ?
-			 tp->write_seq-tp->snd_una :
-			 atomic_read(&sp->wmem_alloc)),
-			(tw_bucket ?
-			 0 :
-			 (format == 0) ?
-			 tp->rcv_nxt-tp->copied_seq :
-			 atomic_read(&sp->rmem_alloc)),
-			timer_active, timer_expires-jiffies,
-			(tw_bucket ? 0 : tp->retransmits),
-			((!tw_bucket && sp->socket) ?
-			 sp->socket->inode->i_uid : 0),
-			(!tw_bucket && timer_active) ? sp->timeout : 0,
-			((!tw_bucket && sp->socket) ?
-			 sp->socket->inode->i_ino : 0));
-
-		len += sprintf(buffer+len, "%-148s\n", tmpbuf);
-		if(len >= length)
-			break;
-	next:
-		sp = sp->sklist_next;
-		i++;
-	}
-	SOCKHASH_UNLOCK_READ();
-
-	begin = len - (pos - offset);
-	*start = buffer + begin;
-	len -= begin;
-	if(len > length)
-		len = length;
-	return len;
-}
-
-/* These get exported and registered with procfs in af_inet6.c at init time. */
-int tcp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-	return get__netinfo6(&tcpv6_prot, buffer, 0, start, offset, length);
-}
-
-int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-	return get__netinfo6(&udpv6_prot, buffer, 1, start, offset, length);
-}
-
-int raw6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-	return get__netinfo6(&rawv6_prot, buffer, 1, start, offset, length);
-}
 
 int afinet6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.3.9/linux/net/ipv6/raw.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv6/raw.c	Mon Jul  5 20:35:18 1999
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.26 1999/06/09 10:11:18 davem Exp $
+ *	$Id: raw.c,v 1.27 1999/07/02 11:26:40 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -39,66 +39,36 @@
 
 #include <net/rawv6.h>
 
-#include <asm/uaccess.h>
-
 struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
 
 static void raw_v6_hash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
+	struct sock **skp = &raw_v6_htable[sk->num & (RAWV6_HTABLE_SIZE - 1)];
 
-	num &= (RAWV6_HTABLE_SIZE - 1);
-	skp = &raw_v6_htable[num];
 	SOCKHASH_LOCK_WRITE();
-	sk->next = *skp;
+	if ((sk->next = *skp) != NULL)
+		(*skp)->pprev = &sk->next;
 	*skp = sk;
-	sk->hashent = num;
+	sk->pprev = skp;
+	sk->prot->inuse++;
+	if(sk->prot->highestinuse < sk->prot->inuse)
+		sk->prot->highestinuse = sk->prot->inuse;
 	SOCKHASH_UNLOCK_WRITE();
 }
 
 static void raw_v6_unhash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
-
-	num &= (RAWV6_HTABLE_SIZE - 1);
-	skp = &raw_v6_htable[num];
-
 	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
+	if (sk->pprev) {
+		if (sk->next)
+			sk->next->pprev = sk->pprev;
+		*sk->pprev = sk->next;
+		sk->pprev = NULL;
+		sk->prot->inuse--;
 	}
 	SOCKHASH_UNLOCK_WRITE();
 }
 
-static void raw_v6_rehash(struct sock *sk)
-{
-	struct sock **skp;
-	int num = sk->num;
-	int oldnum = sk->hashent;
-
-	num &= (RAWV6_HTABLE_SIZE - 1);
-	skp = &raw_v6_htable[oldnum];
-
-	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
-	}
-	sk->next = raw_v6_htable[num];
-	raw_v6_htable[num] = sk;
-	sk->hashent = num;
-	SOCKHASH_UNLOCK_WRITE();
-}
-
 
 /* Grumble... icmp and ip_input want to get at this... */
 struct sock *raw_v6_lookup(struct sock *sk, unsigned short num,
@@ -636,9 +606,80 @@
 	return(0);
 }
 
+static void get_raw6_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	struct in6_addr *dest, *src;
+	__u16 destp, srcp;
+	int timer_active;
+	unsigned long timer_expires;
+
+	dest  = &sp->net_pinfo.af_inet6.daddr;
+	src   = &sp->net_pinfo.af_inet6.rcv_saddr;
+	destp = ntohs(sp->dport);
+	srcp  = ntohs(sp->sport);
+	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
+	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
+	sprintf(tmpbuf,
+		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		i,
+		src->s6_addr32[0], src->s6_addr32[1],
+		src->s6_addr32[2], src->s6_addr32[3], srcp,
+		dest->s6_addr32[0], dest->s6_addr32[1],
+		dest->s6_addr32[2], dest->s6_addr32[3], destp,
+		sp->state, 
+		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
+		timer_active, timer_expires-jiffies, 0,
+		sp->socket->inode->i_uid, timer_active ? sp->timeout : 0,
+		sp->socket ? sp->socket->inode->i_ino : 0);
+}
+
+int raw6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0, num = 0, i;
+	off_t pos = 0;
+	off_t begin;
+	char tmpbuf[150];
+
+	if (offset < 149)
+		len += sprintf(buffer, "%-148s\n",
+			       "  sl  "						/* 6 */
+			       "local_address                         "		/* 38 */
+			       "remote_address                        "		/* 38 */
+			       "st tx_queue rx_queue tr tm->when retrnsmt"	/* 41 */
+			       "   uid  timeout inode");			/* 21 */
+										/*----*/
+										/*144 */
+	pos = 149;
+	SOCKHASH_LOCK_READ();
+	for (i = 0; i < RAWV6_HTABLE_SIZE; i++) {
+		struct sock *sk;
+
+		for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) {
+			if (sk->family != PF_INET6)
+				continue;
+			pos += 149;
+			if (pos < offset)
+				continue;
+			get_raw6_sock(sk, tmpbuf, i);
+			len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+out:
+	SOCKHASH_UNLOCK_READ();
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len > length)
+		len = length;
+	if (len < 0)
+		len = 0; 
+	return len;
+}
+
 struct proto rawv6_prot = {
-	(struct sock *)&rawv6_prot,	/* sklist_next */
-	(struct sock *)&rawv6_prot,	/* sklist_prev */
 	rawv6_close,			/* close */
 	udpv6_connect,			/* connect */
 	NULL,				/* accept */
@@ -658,9 +699,7 @@
 	rawv6_rcv_skb,			/* backlog_rcv */
 	raw_v6_hash,			/* hash */
 	raw_v6_unhash,			/* unhash */
-	raw_v6_rehash,			/* rehash */
-	NULL,				/* good_socknum */
-	NULL,				/* verify_bind */
+	NULL,				/* get_port */
 	128,				/* max_header */
 	0,				/* retransmits */
 	"RAW",				/* name */
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.3.9/linux/net/ipv6/route.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv6/route.c	Mon Jul  5 20:35:18 1999
@@ -37,7 +37,6 @@
 #include <net/ndisc.h>
 #include <net/addrconf.h>
 #include <net/tcp.h>
-#include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.9/linux/net/ipv6/tcp_ipv6.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv6/tcp_ipv6.c	Sat Jul  3 17:57:23 1999
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.108 1999/06/09 08:29:43 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.109 1999/07/02 11:26:41 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -84,101 +84,124 @@
  * But it doesn't matter, the recalculation is in the rarest path
  * this function ever takes.
  */
-static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum)
+static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
 {
 	struct tcp_bind_bucket *tb;
-	int result = 0;
 
 	SOCKHASH_LOCK_WRITE();
-	for(tb = tcp_bhash[tcp_bhashfn(snum)];
-	    (tb && (tb->port != snum));
-	    tb = tb->next)
-		;
-	if(tb && tb->owners) {
-		/* Fast path for reuse ports, see include/net/tcp.h for a very
-		 * detailed description of why this works, and why it is worth
-		 * the effort at all. -DaveM
-		 */
-		if((tb->flags & TCPB_FLAG_FASTREUSE)	&&
-		   (sk->reuse != 0)) {
-			goto go_like_smoke;
+	if (snum == 0) {
+		int rover = tcp_port_rover;
+		int low = sysctl_local_port_range[0];
+		int high = sysctl_local_port_range[1];
+		int remaining = (high - low) + 1;
+
+		do {	rover++;
+			if ((rover < low) || (rover > high))
+				rover = low;
+			tb = tcp_bhash[tcp_bhashfn(rover)];
+			for ( ; tb; tb = tb->next)
+				if (tb->port == rover)
+					goto next;
+			break;
+		next:
+		} while (--remaining > 0);
+		tcp_port_rover = rover;
+
+		/* Exhausted local port range during search? */
+		if (remaining <= 0)
+			goto fail;
+
+		/* OK, here is the one we will use. */
+		snum = rover;
+		tb = NULL;
+	} else {
+		for (tb = tcp_bhash[tcp_bhashfn(snum)];
+		     tb != NULL;
+		     tb = tb->next)
+			if (tb->port == snum)
+				break;
+	}
+	if (tb != NULL && tb->owners != NULL) {
+		if (tb->fastreuse != 0 && sk->reuse != 0) {
+			goto success;
 		} else {
-			struct sock *sk2;
+			struct sock *sk2 = tb->owners;
 			int sk_reuse = sk->reuse;
 			int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
 
 			/* We must walk the whole port owner list in this case. -DaveM */
-			for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) {
-				if(sk->bound_dev_if == sk2->bound_dev_if) {
-					if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) {
-						if(addr_type == IPV6_ADDR_ANY	||
-						   !sk2->rcv_saddr		||
-						   !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
-								  &sk2->net_pinfo.af_inet6.rcv_saddr))
+			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
+				if (sk->bound_dev_if == sk2->bound_dev_if) {
+					if (!sk_reuse	||
+					    !sk2->reuse	||
+					    sk2->state == TCP_LISTEN) {
+						if (!sk2->rcv_saddr	||
+						    !addr_type == IPV6_ADDR_ANY ||
+						    !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+								   &sk2->net_pinfo.af_inet6.rcv_saddr))
 							break;
 					}
 				}
 			}
-			if(sk2 != NULL)
-				result = 1;
-		}
-	}
-	if(result == 0) {
-		if(tb == NULL) {
-			if((tb = tcp_bucket_create(snum)) == NULL)
-				result = 1;
-			else if (sk->reuse && sk->state != TCP_LISTEN)
-				tb->flags |= TCPB_FLAG_FASTREUSE;
-		} else {
-			/* It could be pending garbage collection, this
-			 * kills the race and prevents it from disappearing
-			 * out from under us by the time we use it.  -DaveM
-			 */
-			if(tb->owners == NULL) {
-				if (!(tb->flags & TCPB_FLAG_LOCKED)) {
-					tb->flags = (TCPB_FLAG_LOCKED |
-						     ((sk->reuse &&
-						       sk->state != TCP_LISTEN) ?
-						      TCPB_FLAG_FASTREUSE : 0));
-					tcp_dec_slow_timer(TCP_SLT_BUCKETGC);
-				} else if (!(tb->flags & TCPB_FLAG_GOODSOCKNUM)) {
-					/* Someone is in between the bind
-					 * and the actual connect or listen.
-					 * See if it was a legitimate reuse
-					 * and we are as well, else punt.
-					 */
-					if (sk->reuse == 0 ||
-					    !(tb->flags & TCPB_FLAG_FASTREUSE))
-						result = 1;
-				} else
-					tb->flags &= ~TCPB_FLAG_GOODSOCKNUM;
-			}
+			/* If we found a conflict, fail. */
+			if (sk2 != NULL)
+				goto fail;
 		}
 	}
-go_like_smoke:
+	if (tb == NULL &&
+	    (tb = tcp_bucket_create(snum)) == NULL)
+			goto fail;
+	if (tb->owners == NULL) {
+		if (sk->reuse && sk->state != TCP_LISTEN)
+			tb->fastreuse = 1;
+		else
+			tb->fastreuse = 0;
+	} else if (tb->fastreuse &&
+		   ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
+		tb->fastreuse = 0;
+
+success:
+	sk->num = snum;
+	if ((sk->bind_next = tb->owners) != NULL)
+		tb->owners->bind_pprev = &sk->bind_next;
+	tb->owners = sk;
+	sk->bind_pprev = &tb->owners;
+	sk->prev = (struct sock *) tb;
+
 	SOCKHASH_UNLOCK_WRITE();
-	return result;
+	return 0;
+
+fail:
+	SOCKHASH_UNLOCK_WRITE();
+	return 1;
 }
 
 static void tcp_v6_hash(struct sock *sk)
 {
-	/* Well, I know that it is ugly...
-	   All this ->prot, ->af_specific etc. need LARGE cleanup --ANK
-	 */
-	if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) {
-		tcp_prot.hash(sk);
-		return;
-	}
 	if(sk->state != TCP_CLOSE) {
 		struct sock **skp;
 
+		/* Well, I know that it is ugly...
+		 * All this ->prot, ->af_specific etc. need LARGE cleanup --ANK
+		 */
+		if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) {
+			tcp_prot.hash(sk);
+			return;
+		}
+
+		if(sk->state == TCP_LISTEN)
+			skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+		else
+			skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+
 		SOCKHASH_LOCK_WRITE();
-		skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
 		if((sk->next = *skp) != NULL)
 			(*skp)->pprev = &sk->next;
 		*skp = sk;
 		sk->pprev = skp;
-		tcp_sk_bindify(sk);
+		sk->prot->inuse++;
+		if(sk->prot->highestinuse < sk->prot->inuse)
+			sk->prot->highestinuse = sk->prot->inuse;
 		SOCKHASH_UNLOCK_WRITE();
 	}
 }
@@ -191,39 +214,9 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		tcp_sk_unbindify(sk);
+		sk->prot->inuse--;
 		tcp_reg_zap(sk);
-	}
-	SOCKHASH_UNLOCK_WRITE();
-}
-
-static void tcp_v6_rehash(struct sock *sk)
-{
-	unsigned char state;
-
-	SOCKHASH_LOCK_WRITE();
-	state = sk->state;
-	if(sk->pprev != NULL) {
-		if(sk->next)
-			sk->next->pprev = sk->pprev;
-		*sk->pprev = sk->next;
-		sk->pprev = NULL;
-		tcp_reg_zap(sk);
-	}
-	if(state != TCP_CLOSE) {
-		struct sock **skp;
-
-		if(state == TCP_LISTEN)
-			skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
-		else
-			skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
-
-		if((sk->next = *skp) != NULL)
-			(*skp)->pprev = &sk->next;
-		*skp = sk;
-		sk->pprev = skp;
-		if(state == TCP_LISTEN)
-			tcp_sk_bindify(sk);
+		__tcp_put_port(sk);
 	}
 	SOCKHASH_UNLOCK_WRITE();
 }
@@ -1063,8 +1056,7 @@
 	newsk->rcv_saddr= LOOPBACK4_IPV6;
 
 	newsk->prot->hash(newsk);
-	add_to_prot_sklist(newsk);
-
+	tcp_inherit_port(sk, newsk);
 	sk->data_ready(sk, 0); /* Deliver SIGIO */ 
 
 	return newsk;
@@ -1666,18 +1658,214 @@
 
 	/* Clean up a locked TCP bind bucket, this only happens if a
 	 * port is allocated for a socket, but it never fully connects.
-	 * In which case we will find num to be non-zero and daddr to
-	 * be zero.
 	 */
-	if(ipv6_addr_any(&(sk->net_pinfo.af_inet6.daddr)) && sk->num != 0)
-		tcp_bucket_unlock(sk);
+	if(sk->prev != NULL)
+		tcp_put_port(sk);
 
 	return inet6_destroy_sock(sk);
 }
 
+/* Proc filesystem TCPv6 sock list dumping. */
+static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf, int i)
+{
+	struct in6_addr *dest, *src;
+
+	src = &req->af.v6_req.loc_addr;
+	dest = &req->af.v6_req.rmt_addr;
+	sprintf(tmpbuf,
+		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %d",
+		i,
+		src->s6_addr32[0], src->s6_addr32[1],
+		src->s6_addr32[2], src->s6_addr32[3],
+		ntohs(sk->sport),
+		dest->s6_addr32[0], dest->s6_addr32[1],
+		dest->s6_addr32[2], dest->s6_addr32[3],
+		ntohs(req->rmt_port),
+		TCP_SYN_RECV,
+		0,0, /* could print option size, but that is af dependent. */
+		1,   /* timers active (only the expire timer) */  
+		(unsigned long)(req->expires - jiffies), 
+		req->retrans,
+		sk->socket ? sk->socket->inode->i_uid : 0,
+		0,  /* non standard timer */  
+		0 /* open_requests have no inode */
+		); 
+}
+
+static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	struct in6_addr *dest, *src;
+	__u16 destp, srcp;
+	int timer_active, timer_active1, timer_active2;
+	unsigned long timer_expires;
+	struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
+
+	dest  = &sp->net_pinfo.af_inet6.daddr;
+	src   = &sp->net_pinfo.af_inet6.rcv_saddr;
+	destp = ntohs(sp->dport);
+	srcp  = ntohs(sp->sport);
+	timer_active1 = tp->retransmit_timer.prev != NULL;
+	timer_active2 = sp->timer.prev != NULL;
+	timer_active	= 0;
+	timer_expires	= (unsigned) -1;
+	if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
+		timer_active	= 1;
+		timer_expires	= tp->retransmit_timer.expires;
+	}
+	if (timer_active2 && sp->timer.expires < timer_expires) {
+		timer_active	= 2;
+		timer_expires	= sp->timer.expires;
+	}
+	if(timer_active == 0)
+		timer_expires = jiffies;
+
+	sprintf(tmpbuf,
+		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		i,
+		src->s6_addr32[0], src->s6_addr32[1],
+		src->s6_addr32[2], src->s6_addr32[3], srcp,
+		dest->s6_addr32[0], dest->s6_addr32[1],
+		dest->s6_addr32[2], dest->s6_addr32[3], destp,
+		sp->state, 
+		tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
+		timer_active, timer_expires-jiffies,
+		tp->retransmits,
+		sp->socket ? sp->socket->inode->i_uid : 0,
+		timer_active ? sp->timeout : 0,
+		sp->socket ? sp->socket->inode->i_ino : 0);
+}
+
+static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
+{
+	extern int tcp_tw_death_row_slot;
+	struct in6_addr *dest, *src;
+	__u16 destp, srcp;
+	int slot_dist;
+
+	dest  = &tw->v6_daddr;
+	src   = &tw->v6_rcv_saddr;
+	destp = ntohs(tw->dport);
+	srcp  = ntohs(tw->sport);
+
+	slot_dist = tw->death_slot;
+	if(slot_dist > tcp_tw_death_row_slot)
+		slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
+	else
+		slot_dist = tcp_tw_death_row_slot - slot_dist;
+
+	sprintf(tmpbuf,
+		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+		"%02X %08X:%08X %02X:%08X %08X %5d %8d %d",
+		i,
+		src->s6_addr32[0], src->s6_addr32[1],
+		src->s6_addr32[2], src->s6_addr32[3], srcp,
+		dest->s6_addr32[0], dest->s6_addr32[1],
+		dest->s6_addr32[2], dest->s6_addr32[3], destp,
+		TCP_TIME_WAIT, 0, 0,
+		3, slot_dist * TCP_TWKILL_PERIOD, 0, 0, 0, 0);
+}
+
+int tcp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0, num = 0, i;
+	off_t begin, pos = 0;
+	char tmpbuf[150];
+
+	if(offset < 149)
+		len += sprintf(buffer, "%-148s\n",
+			       "  sl  "						/* 6 */
+			       "local_address                         "		/* 38 */
+			       "remote_address                        "		/* 38 */
+			       "st tx_queue rx_queue tr tm->when retrnsmt"	/* 41 */
+			       "   uid  timeout inode");			/* 21 */
+										/*----*/
+										/*144 */
+
+	pos = 149;
+	SOCKHASH_LOCK_READ();
+
+	/* First, walk listening socket table. */
+	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
+		struct sock *sk = tcp_listening_hash[i];
+
+		for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) {
+			struct open_request *req;
+			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+			if (sk->family != PF_INET6)
+				continue;
+			pos += 149;
+			if (pos >= offset) {
+				get_tcp6_sock(sk, tmpbuf, num);
+				len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+				if (len >= length)
+					goto out;
+			}
+			for (req = tp->syn_wait_queue; req; req = req->dl_next, num++) {
+				if (req->sk)
+					continue;
+				pos += 149;
+				if (pos < offset)
+					continue;
+				get_openreq6(sk, req, tmpbuf, num);
+				len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+				if(len >= length) 
+					goto out;
+			}
+		}
+	}
+
+	/* Next, walk established hash chain. */
+	for (i = 0; i < (tcp_ehash_size >> 1); i++) {
+		struct sock *sk;
+
+		for(sk = tcp_ehash[i]; sk; sk = sk->next, num++) {
+			if (sk->family != PF_INET6)
+				continue;
+			pos += 149;
+			if (pos < offset)
+				continue;
+			get_tcp6_sock(sk, tmpbuf, num);
+			len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+
+	/* Finally, walk time wait buckets. */
+	for (i = (tcp_ehash_size>>1); i < tcp_ehash_size; i++) {
+		struct tcp_tw_bucket *tw;
+		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i];
+		     tw != NULL;
+		     tw = (struct tcp_tw_bucket *)tw->next, num++) {
+			if (tw->family != PF_INET6)
+				continue;
+			pos += 149;
+			if (pos < offset)
+				continue;
+			get_timewait6_sock(tw, tmpbuf, num);
+			len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+
+out:
+	SOCKHASH_UNLOCK_READ();
+
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len > length)
+		len = length;
+	if (len < 0)
+		len = 0; 
+	return len;
+}
+
 struct proto tcpv6_prot = {
-	(struct sock *)&tcpv6_prot,	/* sklist_next */
-	(struct sock *)&tcpv6_prot,	/* sklist_prev */
 	tcp_close,			/* close */
 	tcp_v6_connect,			/* connect */
 	tcp_accept,			/* accept */
@@ -1697,9 +1885,7 @@
 	tcp_v6_do_rcv,			/* backlog_rcv */
 	tcp_v6_hash,			/* hash */
 	tcp_v6_unhash,			/* unhash */
-	tcp_v6_rehash,			/* rehash */
-	tcp_good_socknum,		/* good_socknum */
-	tcp_v6_verify_bind,		/* verify_bind */
+	tcp_v6_get_port,		/* get_port */
 	128,				/* max_header */
 	0,				/* retransmits */
 	"TCPv6",			/* name */
diff -u --recursive --new-file v2.3.9/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.3.9/linux/net/ipv6/udp.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv6/udp.c	Sat Jul  3 17:57:23 1999
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.42 1999/06/09 10:11:24 davem Exp $
+ *	$Id: udp.c,v 1.43 1999/07/02 11:26:44 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -49,104 +49,105 @@
 /* Grrr, addr_type already calculated by caller, but I don't want
  * to add some silly "cookie" argument to this method just for that.
  */
-static int udp_v6_verify_bind(struct sock *sk, unsigned short snum)
+static int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
-	struct sock *sk2;
-	int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
-	int retval = 0, sk_reuse = sk->reuse;
-
-	SOCKHASH_LOCK_READ();
-	for(sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; sk2 = sk2->next) {
-		if((sk2->num == snum) && (sk2 != sk)) {
-			unsigned char state = sk2->state;
-			int sk2_reuse = sk2->reuse;
-
-			/* Two sockets can be bound to the same port if they're
-			 * bound to different interfaces.
-			 */
-
-			if(sk2->bound_dev_if != sk->bound_dev_if)
-				continue;
+	SOCKHASH_LOCK_WRITE();
+	if (snum == 0) {
+		int best_size_so_far, best, result, i;
 
-			if(addr_type == IPV6_ADDR_ANY || (!sk2->rcv_saddr)) {
-				if((!sk2_reuse)			||
-				   (!sk_reuse)			||
-				   (state == TCP_LISTEN)) {
-					retval = 1;
-					break;
-				}
-			} else if(!ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
-						 &sk2->net_pinfo.af_inet6.rcv_saddr)) {
-				if((!sk_reuse)			||
-				   (!sk2_reuse)			||
-				   (state == TCP_LISTEN)) {
-					retval = 1;
-					break;
-				}
+		if (udp_port_rover > sysctl_local_port_range[1] ||
+		    udp_port_rover < sysctl_local_port_range[0])
+			udp_port_rover = sysctl_local_port_range[0];
+		best_size_so_far = 32767;
+		best = result = udp_port_rover;
+		for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+			struct sock *sk;
+			int size;
+
+			sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+			if (!sk) {
+				if (result > sysctl_local_port_range[1])
+					result = sysctl_local_port_range[0] +
+						((result - sysctl_local_port_range[0]) &
+						 (UDP_HTABLE_SIZE - 1));
+				goto gotit;
 			}
+			size = 0;
+			do {
+				if (++size >= best_size_so_far)
+					goto next;
+			} while ((sk = sk->next) != NULL);
+			best_size_so_far = size;
+			best = result;
+		next:
+		}
+		result = best;
+		for(;; result += UDP_HTABLE_SIZE) {
+			if (result > sysctl_local_port_range[1])
+				result = sysctl_local_port_range[0]
+					+ ((result - sysctl_local_port_range[0]) &
+					   (UDP_HTABLE_SIZE - 1));
+			if (!udp_lport_inuse(result))
+				break;
+		}
+gotit:
+		udp_port_rover = snum = result;
+	} else {
+		struct sock *sk2;
+		int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
+
+		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
+		     sk2 != NULL;
+		     sk2 = sk2->next) {
+			if (sk2->num == snum &&
+			    sk2 != sk &&
+			    sk2->bound_dev_if == sk->bound_dev_if &&
+			    (!sk2->rcv_saddr ||
+			     addr_type == IPV6_ADDR_ANY ||
+			     !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+					    &sk2->net_pinfo.af_inet6.rcv_saddr)) &&
+			    (!sk2->reuse || !sk->reuse))
+				goto fail;
 		}
 	}
-	SOCKHASH_UNLOCK_READ();
-	return retval;
+
+	sk->num = snum;
+	SOCKHASH_UNLOCK_WRITE();
+	return 0;
+
+fail:
+	SOCKHASH_UNLOCK_WRITE();
+	return 1;
 }
 
 static void udp_v6_hash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
-
-	num &= (UDP_HTABLE_SIZE - 1);
-	skp = &udp_hash[num];
+	struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)];
 
 	SOCKHASH_LOCK_WRITE();
-	sk->next = *skp;
+	if ((sk->next = *skp) != NULL)
+		(*skp)->pprev = &sk->next;
 	*skp = sk;
-	sk->hashent = num;
+	sk->pprev = skp;
+	sk->prot->inuse++;
+	if(sk->prot->highestinuse < sk->prot->inuse)
+		sk->prot->highestinuse = sk->prot->inuse;
 	SOCKHASH_UNLOCK_WRITE();
 }
 
 static void udp_v6_unhash(struct sock *sk)
 {
-	struct sock **skp;
-	int num = sk->num;
-
-	num &= (UDP_HTABLE_SIZE - 1);
-	skp = &udp_hash[num];
-
 	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
+	if (sk->pprev) {
+		if (sk->next)
+			sk->next->pprev = sk->pprev;
+		*sk->pprev = sk->next;
+		sk->pprev = NULL;
+		sk->prot->inuse--;
 	}
 	SOCKHASH_UNLOCK_WRITE();
 }
 
-static void udp_v6_rehash(struct sock *sk)
-{
-	struct sock **skp;
-	int num = sk->num;
-	int oldnum = sk->hashent;
-
-	num &= (UDP_HTABLE_SIZE - 1);
-	skp = &udp_hash[oldnum];
-
-	SOCKHASH_LOCK_WRITE();
-	while(*skp != NULL) {
-		if(*skp == sk) {
-			*skp = sk->next;
-			break;
-		}
-		skp = &((*skp)->next);
-	}
-	sk->next = udp_hash[num];
-	udp_hash[num] = sk;
-	sk->hashent = num;
-	SOCKHASH_UNLOCK_WRITE();
-}
-
 static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
 				  struct in6_addr *daddr, u16 dport, int dif)
 {
@@ -216,10 +217,10 @@
 	}
 
 	if (addr_len < sizeof(*usin)) 
-	  	return(-EINVAL);
+	  	return -EINVAL;
 
 	if (usin->sin6_family && usin->sin6_family != AF_INET6) 
-	  	return(-EAFNOSUPPORT);
+	  	return -EAFNOSUPPORT;
 
 	fl.fl6_flowlabel = 0;
 	if (np->sndflow) {
@@ -764,7 +765,7 @@
 		return -EMSGSIZE;
 	
 	if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
-		return(-EINVAL);
+		return -EINVAL;
 
 	fl.fl6_flowlabel = 0;
 
@@ -773,13 +774,13 @@
 			return udp_sendmsg(sk, msg, ulen);
 
 		if (addr_len < sizeof(*sin6))
-			return(-EINVAL);
+			return -EINVAL;
 
 		if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
-			return(-EINVAL);
+			return -EINVAL;
 
 		if (sin6->sin6_port == 0)
-			return(-EINVAL);
+			return -EINVAL;
 
 		udh.uh.dest = sin6->sin6_port;
 		daddr = &sin6->sin6_addr;
@@ -800,7 +801,7 @@
 			daddr = &sk->net_pinfo.af_inet6.daddr;
 	} else {
 		if (sk->state != TCP_ESTABLISHED)
-			return(-ENOTCONN);
+			return -ENOTCONN;
 
 		udh.uh.dest = sk->dport;
 		daddr = &sk->net_pinfo.af_inet6.daddr;
@@ -885,10 +886,80 @@
 	"UDPv6"			/* name			*/
 };
 
+static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	struct in6_addr *dest, *src;
+	__u16 destp, srcp;
+	int timer_active;
+	unsigned long timer_expires;
+
+	dest  = &sp->net_pinfo.af_inet6.daddr;
+	src   = &sp->net_pinfo.af_inet6.rcv_saddr;
+	destp = ntohs(sp->dport);
+	srcp  = ntohs(sp->sport);
+	timer_active = (sp->timer.prev != NULL) ? 2 : 0;
+	timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
+	sprintf(tmpbuf,
+		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		i,
+		src->s6_addr32[0], src->s6_addr32[1],
+		src->s6_addr32[2], src->s6_addr32[3], srcp,
+		dest->s6_addr32[0], dest->s6_addr32[1],
+		dest->s6_addr32[2], dest->s6_addr32[3], destp,
+		sp->state, 
+		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
+		timer_active, timer_expires-jiffies, 0,
+		sp->socket->inode->i_uid, timer_active ? sp->timeout : 0,
+		sp->socket ? sp->socket->inode->i_ino : 0);
+}
+
+int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0, num = 0, i;
+	off_t pos = 0;
+	off_t begin;
+	char tmpbuf[150];
+
+	if (offset < 149)
+		len += sprintf(buffer, "%-148s\n",
+			       "  sl  "						/* 6 */
+			       "local_address                         "		/* 38 */
+			       "remote_address                        "		/* 38 */
+			       "st tx_queue rx_queue tr tm->when retrnsmt"	/* 41 */
+			       "   uid  timeout inode");			/* 21 */
+										/*----*/
+										/*144 */
+	pos = 149;
+	SOCKHASH_LOCK_READ();
+	for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+		struct sock *sk;
+
+		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
+			if (sk->family != PF_INET6)
+				continue;
+			pos += 149;
+			if (pos < offset)
+				continue;
+			get_udp6_sock(sk, tmpbuf, i);
+			len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+			if(len >= length)
+				goto out;
+		}
+	}
+out:
+	SOCKHASH_UNLOCK_READ();
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len > length)
+		len = length;
+	if (len < 0)
+		len = 0; 
+	return len;
+}
 
 struct proto udpv6_prot = {
-	(struct sock *)&udpv6_prot,	/* sklist_next */
-	(struct sock *)&udpv6_prot,	/* sklist_prev */
 	udpv6_close,			/* close */
 	udpv6_connect,			/* connect */
 	NULL,				/* accept */
@@ -908,9 +979,7 @@
 	udpv6_queue_rcv_skb,		/* backlog_rcv */
 	udp_v6_hash,			/* hash */
 	udp_v6_unhash,			/* unhash */
-	udp_v6_rehash,			/* rehash */
-	udp_good_socknum,		/* good_socknum */
-	udp_v6_verify_bind,		/* verify_bind */
+	udp_v6_get_port,		/* get_port */
 	128,				/* max_header */
 	0,				/* retransmits */
 	"UDP",				/* name */
diff -u --recursive --new-file v2.3.9/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.3.9/linux/net/ipx/af_ipx.c	Thu Feb 18 19:15:41 1999
+++ linux/net/ipx/af_ipx.c	Mon Jul  5 20:03:14 1999
@@ -794,7 +794,8 @@
 					if(call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb) == FW_ACCEPT)
 					{
 					        skb2=skb_clone(skb, GFP_ATOMIC);
-						ipxrtr_route_skb(skb2);
+						if(skb2)
+							ipxrtr_route_skb(skb2);
 					}
 				}
 			}
diff -u --recursive --new-file v2.3.9/linux/net/irda/compressors/irda_deflate.c linux/net/irda/compressors/irda_deflate.c
--- v2.3.9/linux/net/irda/compressors/irda_deflate.c	Fri Dec 18 08:06:39 1998
+++ linux/net/irda/compressors/irda_deflate.c	Mon Jul  5 20:35:18 1999
@@ -54,7 +54,6 @@
 #include <linux/malloc.h>
 #include <linux/vmalloc.h> 
 #include <linux/errno.h>
-#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 
diff -u --recursive --new-file v2.3.9/linux/net/irda/irmod.c linux/net/irda/irmod.c
--- v2.3.9/linux/net/irda/irmod.c	Mon Jun  7 16:18:58 1999
+++ linux/net/irda/irmod.c	Mon Jul  5 20:03:14 1999
@@ -218,6 +218,8 @@
 	misc_register( &irda.dev);
 
 	irda.in_use = FALSE;
+	
+	init_waitqueue_head(&irda.wait_queue);
 
 	/* 
 	 * Initialize modules that got compiled into the kernel 
diff -u --recursive --new-file v2.3.9/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.3.9/linux/net/netrom/af_netrom.c	Thu Jan  7 09:27:47 1999
+++ linux/net/netrom/af_netrom.c	Mon Jul  5 20:35:18 1999
@@ -63,7 +63,6 @@
 #include <linux/proc_fs.h>
 #include <net/ip.h>
 #include <net/arp.h>
-#include <linux/if_arp.h>
 #include <linux/init.h>
 
 int nr_ndevs = 4;
@@ -1311,6 +1310,11 @@
 
 	for (i = 0; i < nr_ndevs; i++) {
 		dev_nr[i].name = kmalloc(20, GFP_KERNEL);
+		if(dev_nr[i].name==NULL)
+		{
+			printk(KERN_ERR "Netrom: unable to register devices.\n");
+			break;
+		}
 		sprintf(dev_nr[i].name, "nr%d", i);
 		dev_nr[i].init = nr_init;
 		register_netdev(&dev_nr[i]);
diff -u --recursive --new-file v2.3.9/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.9/linux/net/netsyms.c	Wed Jun 16 19:26:27 1999
+++ linux/net/netsyms.c	Mon Jul  5 20:35:18 1999
@@ -25,6 +25,7 @@
 #include <linux/hippidevice.h>
 #endif
 #include <net/pkt_sched.h>
+#include <net/scm.h>
 
 #ifdef CONFIG_BRIDGE
 #include <net/br.h>
@@ -32,7 +33,6 @@
 
 #ifdef CONFIG_INET
 #include <linux/ip.h>
-#include <linux/etherdevice.h>
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/ip.h>
@@ -40,9 +40,7 @@
 #include <net/tcp.h>
 #include <net/icmp.h>
 #include <net/route.h>
-#include <net/scm.h>
 #include <net/inet_common.h>
-#include <net/pkt_sched.h>
 #include <linux/inet.h>
 #include <linux/mroute.h>
 #include <linux/igmp.h>
@@ -56,18 +54,18 @@
 #include <linux/icmpv6.h>
 #include <net/ipv6.h>
 #include <net/ndisc.h>
-#include <net/dst.h>
 #include <net/transp_v6.h>
 
 extern int tcp_tw_death_row_slot;
+extern int sysctl_local_port_range[2];
+extern int tcp_port_rover;
+extern int udp_port_rover;
 #endif
 
 #endif
 
 #include <linux/rtnetlink.h>
 
-#include <net/scm.h>
-
 #if	defined(CONFIG_ULTRA)	||	defined(CONFIG_WD80x3)		|| \
 	defined(CONFIG_EL2)	||	defined(CONFIG_NE2000)		|| \
 	defined(CONFIG_E2100)	||	defined(CONFIG_HPLAN_PLUS)	|| \
@@ -90,10 +88,6 @@
 
 #ifdef CONFIG_ATALK_MODULE
 #include <net/sock.h>
-#include <net/dst.h>
-#include <net/checksum.h>
-#include <linux/etherdevice.h>
-#include <net/pkt_sched.h>
 #endif
 
 #ifdef CONFIG_SYSCTL
@@ -281,13 +275,11 @@
 EXPORT_SYMBOL(inet_recvmsg);
 
 /* Socket demultiplexing. */
-EXPORT_SYMBOL(tcp_good_socknum);
 EXPORT_SYMBOL(tcp_ehash);
 EXPORT_SYMBOL(tcp_ehash_size);
 EXPORT_SYMBOL(tcp_listening_hash);
 EXPORT_SYMBOL(tcp_bhash);
 EXPORT_SYMBOL(tcp_bhash_size);
-EXPORT_SYMBOL(udp_good_socknum);
 EXPORT_SYMBOL(udp_hash);
 
 EXPORT_SYMBOL(destroy_sock);
@@ -328,7 +320,9 @@
 EXPORT_SYMBOL(tcp_v4_conn_request);
 EXPORT_SYMBOL(tcp_create_openreq_child);
 EXPORT_SYMBOL(tcp_bucket_create);
-EXPORT_SYMBOL(tcp_bucket_unlock);
+EXPORT_SYMBOL(__tcp_put_port);
+EXPORT_SYMBOL(tcp_put_port);
+EXPORT_SYMBOL(tcp_inherit_port);
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
 EXPORT_SYMBOL(tcp_v4_do_rcv);
 EXPORT_SYMBOL(tcp_v4_connect);
@@ -344,6 +338,9 @@
 EXPORT_SYMBOL(tcp_connect);
 EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_tw_death_row_slot);
+EXPORT_SYMBOL(sysctl_local_port_range);
+EXPORT_SYMBOL(tcp_port_rover);
+EXPORT_SYMBOL(udp_port_rover);
 EXPORT_SYMBOL(tcp_sync_mss);
 EXPORT_SYMBOL(net_statistics); 
 
diff -u --recursive --new-file v2.3.9/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.3.9/linux/net/rose/af_rose.c	Wed Oct  7 15:52:55 1998
+++ linux/net/rose/af_rose.c	Mon Jul  5 20:35:18 1999
@@ -54,7 +54,6 @@
 #include <linux/proc_fs.h>
 #include <net/ip.h>
 #include <net/arp.h>
-#include <linux/if_arp.h>
 #include <linux/init.h>
 
 int rose_ndevs = 10;
@@ -1509,6 +1508,11 @@
 
 	for (i = 0; i < rose_ndevs; i++) {
 		dev_rose[i].name = kmalloc(20, GFP_KERNEL);
+		if(dev_rose[i].name == NULL)
+		{
+			printk(KERN_ERR "Rose: unable to register ROSE devices.\n");
+			break;
+		}
 		sprintf(dev_rose[i].name, "rose%d", i);
 		dev_rose[i].init = rose_init;
 		register_netdev(&dev_rose[i]);
diff -u --recursive --new-file v2.3.9/linux/net/socket.c linux/net/socket.c
--- v2.3.9/linux/net/socket.c	Wed Jun 30 13:38:20 1999
+++ linux/net/socket.c	Thu Jul  1 10:48:17 1999
@@ -1443,7 +1443,7 @@
 {
 	int i;
 
-	printk(KERN_INFO "Linux NET4.0 for Linux 2.2\n");
+	printk(KERN_INFO "Linux NET4.0 for Linux 2.3\n");
 	printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n");
 
 	/*
diff -u --recursive --new-file v2.3.9/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.3.9/linux/net/sunrpc/xprt.c	Wed Jun 30 13:38:20 1999
+++ linux/net/sunrpc/xprt.c	Sat Jul  3 10:45:04 1999
@@ -362,10 +362,7 @@
 	sk->state_change = xprt->old_state_change;
 	sk->write_space  = xprt->old_write_space;
 
-	if (xprt->file)
-		fput(xprt->file);
-	else
-		sock_release(xprt->sock);
+	sock_release(xprt->sock);
 	/*
 	 *	TCP doesnt require the rpciod now - other things may
 	 *	but rpciod handles that not us.
@@ -1428,39 +1425,6 @@
 		rpciod_up();
 	return xprt;
 }
-
-/*
- * Create and initialize an RPC client given an open file.
- * This is obsolete now.
- */
-#if 0
-struct rpc_xprt *
-xprt_create(struct file *file, struct sockaddr_in *ap, struct rpc_timeout *to)
-{
-	struct rpc_xprt	*xprt;
-	struct socket	*sock;
-	int		proto;
-
-	if (!file) {
-		printk("RPC: file == NULL in xprt_create!\n");
-		return NULL;
-	}
-
-	sock = &file->f_inode->u.socket_i;
-	if (sock->ops->family != PF_INET) {
-		printk(KERN_WARNING "RPC: only INET sockets supported\n");
-		return NULL;
-	}
-
-	proto = (sock->type == SOCK_DGRAM)? IPPROTO_UDP : IPPROTO_TCP;
-	if ((xprt = xprt_setup(sock, proto, ap, to)) != NULL) {
-		xprt->file = file;
-		atomic_inc(&file->f_count);
-	}
-
-	return xprt;
-}
-#endif
 
 /*
  * Bind to a reserved port
diff -u --recursive --new-file v2.3.9/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.9/linux/net/unix/af_unix.c	Wed Jun 30 13:38:20 1999
+++ linux/net/unix/af_unix.c	Mon Jul  5 20:35:18 1999
@@ -87,7 +87,6 @@
 #include <linux/un.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>
-#include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
 #include <linux/in.h>
diff -u --recursive --new-file v2.3.9/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- v2.3.9/linux/net/unix/garbage.c	Wed Jun 30 13:38:20 1999
+++ linux/net/unix/garbage.c	Tue Jul  6 10:11:40 1999
@@ -199,7 +199,7 @@
 		 *	in flight we are in use.
 		 */
 		if(s->socket && s->socket->file &&
-		   atomic_read(&s->socket->file->f_count) > s->protinfo.af_unix.inflight)
+		   file_count(s->socket->file) > s->protinfo.af_unix.inflight)
 			maybe_unmark_and_push(s);
 	}
 
diff -u --recursive --new-file v2.3.9/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.3.9/linux/net/wanrouter/wanproc.c	Wed Jun 30 13:38:20 1999
+++ linux/net/wanrouter/wanproc.c	Sun Jul  4 10:02:30 1999
@@ -123,13 +123,16 @@
 	NULL,			/* rmdir */
 	NULL,			/* mknod */
 	NULL,			/* rename */
-	NULL,			/* follow link */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* get_block */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	router_proc_perms
+	router_proc_perms,	/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /*
@@ -165,15 +168,18 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* get_block */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	router_proc_perms
+	router_proc_perms,	/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /*
- * Proc filesystem derectory entries.
+ * Proc filesystem directory entries.
  */
 
 /*
diff -u --recursive --new-file v2.3.9/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.3.9/linux/net/x25/af_x25.c	Wed Jun  9 14:45:37 1999
+++ linux/net/x25/af_x25.c	Mon Jul  5 20:35:18 1999
@@ -46,7 +46,6 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
-#include <linux/if_arp.h>
 #include <linux/init.h>
 #include <net/x25.h>
 
diff -u --recursive --new-file v2.3.9/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c
--- v2.3.9/linux/net/x25/x25_dev.c	Sun Jul 26 23:35:58 1998
+++ linux/net/x25/x25_dev.c	Mon Jul  5 20:35:18 1999
@@ -43,7 +43,6 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
-#include <linux/if_arp.h>
 #include <linux/firewall.h>
 #include <net/x25.h>
 
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/Makefile linux/scripts/ksymoops/Makefile
--- v2.3.9/linux/scripts/ksymoops/Makefile	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,79 +0,0 @@
-# Description file for ksymoops
-
-#	Thu Nov 26 16:37:46 EST 1998
-#	Version 0.6c
-#	Add -c option.
-
-#	Tue Nov  3 02:31:01 EST 1998
-#	Version 0.6
-#	Read lsmod (/proc/modules).
-#	Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
-#	Upper case variables.
-#	Convert from a.out to bfd, using same format as ksymoops.
-
-DEFS = Makefile ksymoops.h
-
-# Defaults for vmlinux, ksyms, objects, lsmod, System.map.  Externalised so
-# distributions can tweak to suit their own file system layout.
-
-# To default to not reading a source, set to any empty string.
-# To default to reading a source, supply a quoted and escaped string.
-
-# If the string contains *r (*m, *n, *s) then it is replaced at run time by
-# the current value of `uname -r` (-m, -n, -s).  '*' was chosen as something
-# that rarely appears in filenames and does not cause problems like '%' or '$'.
-
-DEF_VMLINUX =				# default no vmlinux
-DEF_OBJECTS = \"/lib/modules/*r/\"	# default current modules
-DEF_KSYMS = \"/proc/ksyms\"		# default current ksyms
-DEF_LSMOD = \"/proc/modules\"		# default current lsmod
-DEF_MAP = \"/usr/src/linux/System.map\"	# default current map
-DEF_CODE_BYTES = 1			# default bytes per code unit
-
-# RedHat users might want defaults like these
-# DEF_MAP = \"/boot/System.map-*r\"
-# DEF_OBJECTS = \"/boot/module-info-*r\"
-
-PROGS = ksymoops
-
-CC=gcc
-CFLAGS = -Dlinux \
-	 -Wall \
-	 -Wno-conversion \
-	 -Waggregate-return \
-	 -Wstrict-prototypes \
-	 -Wmissing-prototypes \
-	 $(DEBUG)
-
-ifneq ($(strip $(DEF_VMLINUX)),)
-	CFLAGS += -DDEF_VMLINUX=$(strip $(DEF_VMLINUX))
-endif
-ifneq ($(strip $(DEF_OBJECTS)),)
-	CFLAGS += -DDEF_OBJECTS=$(strip $(DEF_OBJECTS))
-endif
-ifneq ($(strip $(DEF_KSYMS)),)
-	CFLAGS += -DDEF_KSYMS=$(strip $(DEF_KSYMS))
-endif
-ifneq ($(strip $(DEF_LSMOD)),)
-	CFLAGS += -DDEF_LSMOD=$(strip $(DEF_LSMOD))
-endif
-ifneq ($(strip $(DEF_MAP)),)
-	CFLAGS += -DDEF_MAP=$(strip $(DEF_MAP))
-endif
-
-CFLAGS += -DDEF_CODE_BYTES=$(strip $(DEF_CODE_BYTES))
-
-OBJECTS = io.o ksyms.o ksymoops.o map.o misc.o object.o oops.o re.o symbol.o
-
-all: 	$(PROGS)
-
-:	$(OBJECTS)
-
-$(OBJECTS): $(DEFS)
-
-$(PROGS): %: %.o $(DEFS) $(OBJECTS)
-	$(CC) $(OBJECTS) $(CFLAGS) -lbfd -liberty -o $@
-	-@size $@
-
-clean:
-	rm -f core *.o $(PROGS)
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/README linux/scripts/ksymoops/README
--- v2.3.9/linux/scripts/ksymoops/README	Mon Mar 15 16:12:14 1999
+++ linux/scripts/ksymoops/README	Thu Jul  1 10:54:31 1999
@@ -1,399 +1,7 @@
-  ksymoops.
+ksymoops has been removed from the kernel.  It was always meant to be a
+free standing utility, not linked to any particular kernel version.
+The latest version can be found in ftp://ftp.ocs.com.au/pub/ksymoops,
+together with patches to other utilities in order to give more accurate
+Oops debugging.
 
-  Read a kernel Oops file and make the best stab at converting the code to
-  instructions and mapping stack values to kernel symbols.
-
-  Copyright Keith Owens <kaos@ocs.com.au>.
-  Released under the GNU Public Licence, Version 2.
-
-  To compile, simply type "make" in the ksymoops directory.
-
-  TESTERS WANTED.
-
-  ksymoops handles ix86.  It appears to handle Alpha, Sparc, M68K, PPC,
-  MIPS but I have no machine to test on.  I would appreciate feedback
-  from users of non ix86 machines.  In particular, it would be nice if
-  you could run
-
-   ksymoops -VMO -k /proc/ksyms -dd <oops.file >/tmp/ksymoops.log 2>&1
-
-  and mail /tmp/ksymoops.log to kaos@ocs.com.au
-
-  TODO:
-  Clean up these docs.
-  Tweak System.map to include arch information.
-  Tweak modutils to log at least one symbol for each module loaded,
-  otherwise they are invisible to ksymoops.  Also arch and version data.
-  Include sparc/sparc64 patches from Jakub Jelinek <jj@sunsite.mff.cuni.cz>.
-  Add object format override for sparc/soparc64 or any cross platform
-  oops debugging.
-
-  Mon Jan  4 09:48:13 EST 1999
-  Version 0.6e
-  Added to kernel.
-  Add ARM support.
-  Typo in oops_code.
-  Add -c option.
-  Add -1 option.
-  Report if options were specified or defaulted.
-  Remove false warnings when comparing ksyms and lsmod.
-  Performance inprovements.
-
-  Wed Oct 28 23:14:55 EST 1998
-  Version 0.5
-  No longer read vmlinux by default, it only duplicates System.map.
-
-  Wed Oct 28 13:46:39 EST 1998
-  Version 0.4
-  Split into separate sources.
-
-  Mon Oct 26 00:01:47 EST 1998
-  Version 0.3c
-  Add alpha (arm) processing.
-
-  Mon Oct 26 00:01:47 EST 1998
-  Version 0.3b
-  Add sparc processing.
-  Handle kernel symbol versions.
-
-  Fri Oct 23 13:11:20 EST 1998
-  Version 0.3
-  Add -follow to find command for people who use symlinks to modules.
-  Add Version_ checking.
-
-  Thu Oct 22 22:28:30 EST 1998
-  Version 0.2.
-  Generalise text prefix handling.
-  Handle messages on Code: line.
-  Format addresses with leading zeroes.
-  Minor bug fixes.
-
-  Wed Oct 21 23:28:48 EST 1998
-  Version 0.1.  Rewrite from scratch in C.
-
-  CREDITS.
-  Oops disassembly based on ksymoops.cc,
-    Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
-  m68k code based on ksymoops.cc changes by
-    Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-
-  This code subsumes the Perl script make_System.map.pl which is no longer
-  supported.
-
-  Why another ksymoops I hear you ask?  Various complaints about
-  ksymoops.cc -
-
-  * It requires C++.
-  * It has hard wired limitations on the number of symbols.
-  * It does not handle modules at all.
-  * Very rigid requirements on the format of input, especially the Oops
-    log.
-  * No cross checking between ksyms, modules, System.map etc.
-  * Very little error checking, diagnostics are not suitable for
-    beginners.
-  * It only prints the trace and decoded code, users have to manually
-    extract the other lines from the Oops.
-  * Gives up on the slightest problem.
-  * Only handles i386 and possibly m68k.  The code is difficult to extend
-    to other architectures.
-  * Stops after the first Oops, you have to manually extract each one and
-    run through ksymoops one at a time.
-
-  This version is -
-  * C.
-  * No hard wired limitations (malloc as far as the eye can see).
-  * Handles modules by default.
-  * Uses regular pattern matching so it is a lot more forgiving about
-    input formats.
-  * By default, cross checks ksyms, modules, System.map and vmlinux.
-  * Lots of diagnostics and error checking.
-  * Prints all relevant lines for a complete Oops report.
-  * Tries to provide output no matter how bad the input is.  The level of
-     progress and error reporting is aimed at beginners.
-  * Handles i386, alpha, sparc, sparc64, m68k.  It is a lot easier to extend
-    to other architectures (patches and/or sample data gratefully accepted).
-  * Handles all Oops in the input file(s).
-
-
-  Usage:	ksymoops
-		  [-v vmlinux]	Where to read vmlinux
-		  [-V]		No vmlinux is available
-		  [-o object_dir]	Directory containing modules
-		  [-O]		No modules is available
-		  [-k ksyms]	Where to read ksyms
-		  [-K]		No ksyms is available
-		  [-l lsmod]	Where to read lsmod
-		  [-L]		No lsmod is available
-		  [-m system.map]	Where to read System.map
-		  [-M]		No System.map is available
-		  [-s save.map]	Save consolidated map
-		  [-c code_bytes]	How many bytes in each unit of code
-		  [-1]		One shot toggle (exit after first Oops)
-		  [-d]		Increase debug level by 1
-		  [-h]		Print help text
-		  Oops.file	Oops to decode
-
-	  All flags can occur more than once.  With the exception of -o
-	  and -d which are cumulative, the last occurrence of each flag is
-	  used.  Note that "-v my.vmlinux -V" will be taken as "No vmlinux
-	  available" but "-V -v my.vmlinux" will read my.vmlinux.  You
-	  will be warned about such combinations.
-
-	  Each occurrence of -d increases the debug level.
-
-	  Each -o flag can refer to a directory or to a single object
-	  file.  If a directory is specified then all *.o files in that
-	  directory and its subdirectories are assumed to be modules.
-
-	  If any of the vmlinux, object_dir, ksyms or system.map options
-	  contain the string *r (*m, *n, *s) then it is replaced at run time
-	  by the current value of `uname -r` (-m, -n, -s).
-
-	  The defaults can be changed in the Makefile, typical options are
-
-	  Defaults:	  -V
-			  -o /lib/modules/%r
-			  -k /proc/ksyms
-			  -l /proc/modules
-			  -m /usr/src/linux/System.map
-			  -c 1
-			  Oops report is read from stdin
-
-  Note:	  Unless you tell ksymoops *NOT* to read a particular file, it
-	  will try to read and reconcile almost all possible sources of kernel
-	  symbol information.  This is intended for beginners, they just
-	  type
-
-	    ksymoops < /var/log/syslog
-
-	  no thinking required.  Experts can point at different files or
-	  suppress the input from selected files.  For example, if you
-	  save /proc/ksyms before doing a test that creates an Oops, you
-	  can point ksymoops at the saved ksyms instead of using
-	  /proc/ksyms.
-
-	  vmlinux is not read by default, it only duplicates the
-	  information in System.map.  If you want to read vmlinux as well
-	  as or instead of System.map, use -v.
-
-	  To get the equivalent of the old ksymoops.cc (no vmlinux, no
-	  modules objects, no ksyms, no System.map) just do ksymoops
-	  -VOKLM.  Or to just read System.map, ksymoops -VOKL -m mapfile.
-
-
-  Return codes:	  0 - normal.
-		  1 - error(s) or warning(s) issued, results may not be
-		      reliable.
-		  2 - fatal error, no useful results.
-		  3 - One shot mode, end of input reached.
-
-  Supported architectures
-
-	  i386 tested.
-          m68k code derived from ksymoops.cc and reading traps.c, untested.
-	  MIPS tested.
-	  Sparc tested.
-	  Sparc64 tested.
-	  Alpha tested.
-	  ARM tested.
-
-	  The term "eip" is generic, for example it includes the i386 EIP
-	  and the m68k PC.  Remember that objdump output always says EIP,
-	  no matter what the architecture, see objfile_head.
-
-	  To support another arch, check the Oops_ procedures between
-	  'Start architecture sensitive code' and 'End architecture
-	  sensitive code'.
-
-	  The pattern matching should take care of different lengths for
-	  the address, i.e. addresses should not be arch sensitive.  I
-	  assume that all addresses are at least 4 characters.
-
-	  If nm output has a different format on your arch, check for uses
-	  of re_nm.
-
-
-
-  Because ksymoops reads kernel information from multiple sources, there
-  could be mismatches.  ksymoops does the following cross checks, but only
-  if the specified files exist -
-
-  * Compare Version_nnn numbers from all sources against each other.  Pity
-    that only vmlinux and System.map have these symbols (as at 2.1.125),
-    however I check ksyms, modules and Oops as well.  If somebody adds
-    symbol Version_nnn to ksyms or modules or adds a Version_nnn line to
-    the Oops log, this code is ready.
-
-  * Compare kernel ksyms against vmlinux.  vmlinux takes precedence.
-
-  * Compare System.map against vmlinux.   vmlinux takes precedence.
-
-  * Compare vmlinux against System.map.   vmlinux takes precedence.
-
-  * Compare kernel ksyms against System.map.  System.map takes precedence.
-
-  * Compare modules against module ksyms.  modules take precedence.  Only
-    if at least one module appears in ksyms.
-
-  * Compare module names in ksyms against lsmod.  Warn if a module
-    appears in lsmod but not in ksyms.  Error if a modules appears in
-    ksyms but is not in lsmod.  Only if both ksyms and lsmod have being
-    read.
-
-  The precedence order is somewhat arbitrary, however it only applies if
-  there is any difference between the various sources.
-
-  Handling modules is awkward.  They can be loaded under different names
-  (insmod -o dummy1 dummy.o) and the text, data and read only data are
-  loaded at different offsets.  Although you can give the -m option to
-  insmod which will output the module map when it is loaded, this has a
-  few problems -
-
-  * No equivalent for removing a module.  If you load and remove a lot of
-    modules, you end up with multiple sets of symbols around the same
-    offsets, which set is correct?
-
-  * "insmod -o dummy1 dummy.o" still reports as dummy.  That is, there is
-     no way of telling which particular version of a multiply loaded
-     module the insmod output refers to.  Therefore there is no way of
-     telling which instantiation failed.
-
-  * Even if the above problems are fixed, how do you tell what the module
-    environment looked like when the Oops occurred?  What if a module is
-    loaded or removed just after Oops, how is the user expected to edit
-    the insmod log?  Rule 1 - make ksymoops easy for beginners.
-
-  Although those problems could be fixed, they require changes to
-  modutils.  Working from ksyms and the module objects can be done without
-  changing modutils and without confusing beginners.
-  
-  Alas the ksyms plus object approach has another problem - matching ksyms
-  to module objects.  Nowhere does the kernel say that module dummy1 came
-  from module /lib/modules/2.1.215/net/dummy.o, ksyms just says dummy1.  I
-  have to match ksyms to the relevant object by finding a globally unique
-  external symbol in each module that can be used to map to the external
-  symbols in ksyms.  This assumes that each module exports at least one
-  text symbol that is unique amongst all modules.
-
-  It may not be possible to correctly map other sections such as data and
-  readonly data for modules because they may not have exported symbols.
-  Since the main aim of ksymoops is to map a code Oops, this should not be
-  a problem.
-
-  Unfortunately some modules export no symbols.  They are marked as
-  EXPORT_NO_SYMBOLS are simply do not export anything.  It is
-  impossible to detect these in ksyms because, by definition, ksyms
-  only contains exported symbols for modules.  Since all modules appear
-  in lsmod (/proc/modules), a cross check of lsmod against the module
-  names will find loaded modules with no symbols, at least I can warn
-  about these.
-
-  After merging the various sources, ksymoops has a (hopefully) accurate
-  map including modules.  The -s option lets you save the merged
-  System.map, but remember that module data and readonly data sections may
-  not be correctly relocated, see above.
-
-  Environment Variables.
-  KSYMOOPS_NM		path for nm, defaults to /usr/bin/nm.
-  KSYMOOPS_FIND		path for find, defaults to /usr/bin/find.
-  KSYMOOPS_OBJDUMP	path for objdump, defaults to /usr/bin/objdump.
-
-
-  Input Oops data.
-
-  The ideal input is to feed the syslog straight into this program.  If
-  you cannot do that, you need to know what the program looks for.
-  Especially if you are typing in the Oops by hand :(.  All input is case
-  insensitive.
-
-  * White space in this context means space or tab.  It does not include
-    newline.
-
-  * Oops in syslog has a syslog prefix.  Leading text up to and including
-    ' kernel: ' is always ignored, there is no need to edit syslog first.
-    This leading text need not exist but if it does, it must end in
-    ' kernel: '.
-
-  * An alternative prefix is <n> where n is the kernel print level.  Also
-    ignored if present.
-
-  * Leading white space is treated as a prefix and ignored, the input is
-    not indentation sensitive.
-
-  * In the following paragraphs, assume that any prefixes have been
-    skipped.  If there is more than one prefix, all are skipped, no matter
-    which order they appear in.
-
-  * A bracketed address is optional '[', required '<', at least 4 hex
-    digits, required '>', optional ']'.  For example [<01234567>] or
-    <1234>.
-
-  * The ix86 EIP line is identified by optional white space followed by
-    'EIP:', followed by a least one white space, followed by a bracketed
-    address.
-
-  * The m68k PC line is identified by optional white space followed by
-    'PC', optionally followed by white space, followed by '=', optionally
-    followed by white space, followed by a bracketed address.
-
-  * The sparc PC line starts with PSR and PC is the second hex value, not
-    bracketed.
-
-  * The sparc64 TPC line starts with TSTATE and TPC is the second hex value,
-    not bracketed.
-
-  * A call trace line is identified by 'Call Trace:' followed by at least
-    one white space.  Or it is a line starting with a bracketed address,
-    but only if the previous line was a call trace line (I hate multi line
-    output that relies on identation for recognition, especially when
-    lines can have a variable prefix).
-
-  * The Code line is identified by 'Code:' followed by a least one white
-    space character followed by at least one hex value.  The line can
-    contain multiple hex values, each separated by at least one white
-    space.  Each hex value must be 2 to 8 digits and must be a multiple of
-    2 digits.
-
-    On some architectures the Code: data is a stream of single bytes,
-    in machine order.  On other architectures, it is a stream of shorts
-    or ints in human readable order which does not always match the
-    machine order, endianess raises its ugly head.  We are consistently
-    inconsistent.
-
-    To cater for these architecture inconsistencies, use the -c option.
-    If the Code: line is already in machine order, use -c 1.  If the
-    Code: data is a stream of shorts or ints which do not match the
-    machine order, use -c 2 or -c 4.  Each set of 'c' bytes are swapped
-    to (hopefully) reflect the machine order.
-
-    Special cases where Code: can be followed by text.
-      'Code: general protection'
-      'Code: <n>'
-    Dump the data anyway, the code was unavailable.
-
-  * Formatted data is only output when the Code: line is seen.  If any
-    data has been stored and more than 5 lines other than Oops text (see
-    Oops_print) or end of file are encountered then ksymoops assumes that
-    the Code: line is missing or garbled and dumps the formatted data
-    anyway.  Fail safe, I hope.
-
-  * By default, ksymoops reads its entire input file.  If the -1 toggle
-    is set, it will run in one shot mode and exit after the first Oops.
-    This is useful for automatically mailing reports as they happen,
-    like this :-
-
-    #!/bin/sh
-    # ksymoops1
-    while (true)
-    do
-    	ksymoops -1 > $HOME/oops1
-	if [ $? -eq 3 ]
-	then
-	   exit 0
-	fi
-	mail -s Oops admin < $HOME/oops1
-    done
-
-    tail -f /var/log/messages | ksymoops1
-
-    Restarting after log rotation is left as an exercise for the reader.
+Keith Owens <kaos@ocs.com.au> Sat Jun 19 10:30:34 EST 1999
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/io.c linux/scripts/ksymoops/io.c
--- v2.3.9/linux/scripts/ksymoops/io.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/io.c	Wed Dec 31 16:00:00 1969
@@ -1,139 +0,0 @@
-/*
-	io.c.
-
-	Local I/O routines for ksymoops.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	fwrite_local is redundant, replaced by bfd.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
-
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-#include <sys/stat.h>
-
-int regular_file(const char *file, const char *msg)
-{
-	struct stat statbuf;
-	if (stat(file, &statbuf)) {
-		fprintf(stderr, "%s: %s stat %s failed",
-			prefix, msg, file);
-		perror(" ");
-		++errors;
-		return 0;
-	}
-
-	if (!S_ISREG(statbuf.st_mode)) {
-		fprintf(stderr,
-			"%s: %s %s is not a regular file, ignored\n",
-			prefix, msg, file);
-		++errors;
-		return 0;
-	}
-	return 1;
-}
-
-FILE *fopen_local(const char *file, const char *mode, const char *msg)
-{
-	FILE *f;
-	if (!(f = fopen(file, mode))) {
-		fprintf(stderr, "%s: %s fopen '%s' failed",
-			prefix, msg, file);
-		perror(" ");
-		++errors;
-	}
-	return f;
-}
-
-void fclose_local(FILE *f, const char *msg)
-{
-	int i;
-	if ((i = fclose(f))) {
-		fprintf(stderr, "%s: %s fclose failed %d", prefix, msg, i);
-		perror(" ");
-		++errors;
-	}
-}
-
-/* Read a line, increasing the size of the line as necessary until \n is read */
-#define INCREMENT 10	/* arbitrary */
-char *fgets_local(char **line, int *size, FILE *f, const char *msg)
-{
-	char *l, *p, *r;
-	int longline = 1;
-
-	if (!*line) {
-		*size = INCREMENT;
-		*line = malloc(*size);
-		if (!*line)
-			malloc_error("fgets_local alloc line");
-	}
-
-	l = *line;
-	while (longline) {
-		r = fgets(l, *size-(l-*line), f);
-		if (!r) {
-			if (ferror(f)) {
-				fprintf(stderr,
-					"%s: %s fgets failed", prefix, msg);
-				perror(" ");
-				++errors;
-			}
-			if (l != *line)
-				return(*line);
-			else
-				return(r);
-		}
-		if (!(p = strchr(*line, '\n'))) {
-			*size += INCREMENT;
-			*line = realloc(*line, *size);
-			if (!*line)
-				malloc_error("fgets_local realloc line");
-			l = *line+*size-INCREMENT-1;
-		}
-		else {
-			*p = '\0';
-			longline = 0;
-		}
-	}
-
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s line '%s'\n", msg, *line);
-	return(*line);
-}
-
-FILE *popen_local(const char *cmd, const char *msg)
-{
-	FILE *f;
-	if (!(f = popen(cmd, "r"))) {
-		fprintf(stderr, "%s: %s popen '%s' failed",
-			prefix, msg, cmd);
-		perror(" ");
-		++errors;
-	}
-	return f;
-}
-
-void pclose_local(FILE *f, const char *msg)
-{
-	int i;
-	errno = 0;
-	if ((i = pclose(f))) {
-		fprintf(stderr, "%s: %s pclose failed 0x%x", prefix, msg, i);
-		if (errno)
-			perror(" ");
-		else
-			fprintf(stderr, "\n");
-		++errors;
-	}
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/ksymoops.c linux/scripts/ksymoops/ksymoops.c
--- v2.3.9/linux/scripts/ksymoops/ksymoops.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/ksymoops.c	Wed Dec 31 16:00:00 1969
@@ -1,678 +0,0 @@
-/*
-	ksymoops.c.
-
-	Read a kernel Oops file and make the best stab at converting the code to
-	instructions and mapping stack values to kernel symbols.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-*/
-
-#define VERSION "0.6e"
-
-/*
-
-	Tue Jan  5 19:26:02 EST 1999
-	Version 0.6e
-	Added to kernel.
-
-	Mon Jan  4 09:48:13 EST 1999
-	Version 0.6d
-	Add ARM support.
-
-	Thu Nov 26 16:37:46 EST 1998
-	Version 0.6c
-	Typo in oops_code.
-	Add -c option.
-	Add -1 option.
-	Report if options were specified or defaulted.
-
-	Fri Nov  6 10:38:42 EST 1998
-	Version 0.6b
-	Remove false warnings when comparing ksyms and lsmod.
-
-	Tue Nov  3 23:33:04 EST 1998
-	Version 0.6a
-	Performance inprovements.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Read lsmod (/proc/modules).
-	Ignore addresses 0-4095 when mapping address to symbol.
-	Discard default objects if -o specified.
-	Oops file must be regular.
-	Add "invalid operand" to Oops_print.
-	Move "Using_Version" copy to map.c.
-	Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
-	Minor adjustment to re for ppc.
-	Minor adjustment to re for objdump lines with <_EIP+xxx>.
-	Convert from a.out to bfd, using same format as ksymoops.
-	Added MIPS.
-	PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
-
-	Wed Oct 28 23:14:55 EST 1998
-	Version 0.5
-	No longer read vmlinux by default, it only duplicates System.map.
-
-	Wed Oct 28 13:47:38 EST 1998
-	Version 0.4
-	Split into separate sources.
-
-	Mon Oct 26 00:01:47 EST 1998
-	Version 0.3c
-	Add alpha (arm) processing.
-
-	Mon Oct 26 00:01:47 EST 1998
-	Version 0.3b
-	Add sparc processing.
-	Handle kernel symbol versions.
-
-	Fri Oct 23 13:11:20 EST 1998
-	Version 0.3
-	Add -follow to find command for people who use symlinks to modules.
-	Add Version_ checking.
-
-	Thu Oct 22 22:28:30 EST 1998
-	Version 0.2.
-	Generalise text prefix handling.
-	Handle messages on Code: line.
-	Format addresses with leading zeroes.
-	Minor bug fixes.
-
-	Wed Oct 21 23:28:48 EST 1998
-	Version 0.1.  Rewrite from scratch in C.
-
-	CREDITS.
-	Oops disassembly based on ksymoops.cc,
-	  Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
-	m68k code based on ksymoops.cc changes by
-	  Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- */
-
-#include "ksymoops.h"
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-
-char *prefix;
-char *path_nm = "/usr/bin/nm";			/* env KSYMOOPS_NM */
-char *path_find = "/usr/bin/find";		/* env KSYMOOPS_FIND */
-char *path_objdump = "/usr/bin/objdump";	/* env KSYMOOPS_OBJDUMP */
-int debug = 0;
-int errors = 0;
-int warnings = 0;
-
-SYMBOL_SET  ss_vmlinux;
-SYMBOL_SET  ss_ksyms_base;
-SYMBOL_SET *ss_ksyms_module;
-int         ss_ksyms_modules;
-SYMBOL_SET  ss_lsmod;
-SYMBOL_SET *ss_object;
-int         ss_objects;
-SYMBOL_SET  ss_system_map;
-
-SYMBOL_SET  ss_merged;   /* merged map with info from all sources */
-SYMBOL_SET  ss_Version;  /* Version_ numbers where available */
-
-/* Regular expression stuff */
-
-regex_t     re_nm;
-regmatch_t *re_nm_pmatch;
-regex_t     re_bracketed_address;
-regmatch_t *re_bracketed_address_pmatch;
-regex_t     re_unbracketed_address;
-regmatch_t *re_unbracketed_address_pmatch;
-
-static void usage(void)
-{
-	fprintf(stderr, "Version " VERSION "\n");
-	fprintf(stderr, "usage: %s\n", prefix);
-	fprintf(stderr,
-		"\t\t[-v vmlinux]\tWhere to read vmlinux\n"
-		"\t\t[-V]\t\tNo vmlinux is available\n"
-		"\t\t[-o object_dir]\tDirectory containing modules\n"
-		"\t\t[-O]\t\tNo modules is available\n"
-		"\t\t[-k ksyms]\tWhere to read ksyms\n"
-		"\t\t[-K]\t\tNo ksyms is available\n"
-		"\t\t[-l lsmod]\tWhere to read lsmod\n"
-		"\t\t[-L]\t\tNo lsmod is available\n"
-		"\t\t[-m system.map]\tWhere to read System.map\n"
-		"\t\t[-M]\t\tNo System.map is available\n"
-		"\t\t[-s save.map]\tSave consolidated map\n"
-		"\t\t[-d]\t\tIncrease debug level by 1\n"
-		"\t\t[-h]\t\tPrint help text\n"
-		"\t\t[-c code_bytes]\tHow many bytes in each unit of code\n"
-		"\t\t[-1]\t\tOne shot toggle (exit after first Oops)\n"
-		"\t\t<Oops.file\tOops report to decode\n"
-		"\n"
-		"\t\tAll flags can occur more than once.  With the exception "
-			"of -o\n"
-		"\t\tand -d which are cumulative, the last occurrence of each "
-			"flag is\n"
-		"\t\tused.  Note that \"-v my.vmlinux -V\" will be taken as "
-			"\"No vmlinux\n"
-		"\t\tavailable\" but \"-V -v my.vmlinux\" will read "
-			"my.vmlinux.  You\n"
-		"\t\twill be warned about such combinations.\n"
-		"\n"
-		"\t\tEach occurrence of -d increases the debug level.\n"
-		"\n"
-		"\t\tEach -o flag can refer to a directory or to a single "
-			"object\n"
-		"\t\tfile.  If a directory is specified then all *.o files in "
-			"that\n"
-		"\t\tdirectory and its subdirectories are assumed to be "
-			"modules.\n"
-		"\n"
-		"\t\tIf any of the vmlinux, object_dir, ksyms or system.map "
-		"options\n"
-		"\t\tcontain the string *r (*m, *n, *s) then it is replaced "
-		"at run\n"
-		"\t\ttime by the current value of `uname -r` (-m, -n, -s).\n"
-		"\n"
-		"\t\tThe defaults can be changed in the Makefile, current "
-		"defaults\n"
-		"\t\tare\n\n"
-		"\t\t\t"
-#ifdef DEF_VMLINUX
-		"-v " DEF_LINUX
-#else
-		"-V"
-#endif
-		"\n"
-		"\t\t\t"
-#ifdef DEF_OBJECTS
-		"-o " DEF_OBJECTS
-#else
-		"-O"
-#endif
-		"\n"
-		"\t\t\t"
-#ifdef DEF_KSYMS
-		"-k " DEF_KSYMS
-#else
-		"-K"
-#endif
-		"\n"
-		"\t\t\t"
-#ifdef DEF_LSMOD
-		"-l " DEF_LSMOD
-#else
-		"-L"
-#endif
-		"\n"
-		"\t\t\t"
-#ifdef DEF_MAP
-		"-m " DEF_MAP
-#else
-		"-M"
-#endif
-		"\n"
-		"\t\t\t-c %d\n"	/* DEF_CODE_BYTES */
-		"\t\t\tOops report is read from stdin\n"
-		"\n",
-	DEF_CODE_BYTES
-	       );
-}
-
-/* Check if possibly conflicting options were specified */
-static void multi_opt(int specl, int specu, char type, const char *using)
-{
-	if (specl && specu) {
-		fprintf(stderr,
-			"Warning - you specified both -%c and -%c.  Using '",
-			type, toupper(type));
-		++warnings;
-		if (using) {
-			fprintf(stderr, "-%c %s", type, using);
-			if (type == 'o')
-				fprintf(stderr, " ...");
-			fprintf(stderr, "'\n");
-		}
-		else
-			fprintf(stderr, "-%c'\n", toupper(type));
-	}
-	else if (specl > 1 && type != 'o') {
-		fprintf(stderr,
-			"Warning - you specified -%c more than once.  "
-			"Using '-%c %s'\n",
-			type, type, using);
-		++warnings;
-	}
-	else if (specu > 1) {
-		fprintf(stderr,
-			"Warning - you specified -%c more than once.  "
-			"Second and subsequent '-%c' ignored\n",
-			toupper(type), toupper(type));
-		++warnings;
-	}
-}
-
-/* If a name contains *r (*m, *n, *s), replace with the current value of
- * `uname -r` (-m, -n, -s).  Actually uses uname system call rather than the
- * uname command but the result is the same.
- */
-static void convert_uname(char **name)
-{
-	char *p, *newname, *oldname, *replacement;
-	unsigned len;
-	int free_oldname = 0;
-	static char procname[] = "convert_uname";
-
-	if (!*name)
-		return;
-
-	while ((p = strchr(*name, '*'))) {
-		struct utsname buf;
-		int i = uname(&buf);
-		if (debug)
-			fprintf(stderr, "DEBUG: %s %s in\n", procname, *name);
-		if (i) {
-			fprintf(stderr,
-				"%s: uname failed, %s will not be processed\n",
-				prefix, *name);
-			perror(prefix);
-			++errors;
-			return;
-		}
-		switch (*(p+1)) {
-		case 'r':
-			replacement = buf.release;
-			break;
-		case 'm':
-			replacement = buf.machine;
-			break;
-		case 'n':
-			replacement = buf.nodename;
-			break;
-		case 's':
-			replacement = buf.sysname;
-			break;
-		default:
-			fprintf(stderr,
-				"%s: invalid replacement character '*%c' "
-				"in %s\n",
-				prefix, *(p+1), *name);
-			++errors;
-			return;
-		}
-		len = strlen(*name)-2+strlen(replacement)+1;
-		if (!(newname = malloc(len)))
-			malloc_error(procname);
-		strncpy(newname, *name, (p-*name));
-		strcpy(newname+(p-*name), replacement);
-		strcpy(newname+(p-*name)+strlen(replacement), p+2);
-		p = newname+(p-*name)+strlen(replacement);	/* no rescan */
-		oldname = *name;
-		*name = newname;
-		if (free_oldname)
-			free(oldname);
-		free_oldname = 1;
-		if (debug)
-			fprintf(stderr, "DEBUG: %s %s out\n", procname, *name);
-	}
-	return;
-}
-
-/* Report if the option was specified or defaulted */
-static void spec_or_default(int spec, int *some_spec) {
-	if (spec) {
-		printf(" (specified)\n");
-		if (some_spec)
-			*some_spec = 1;
-	}
-	else
-		printf(" (default)\n");
-}
-
-/* Parse the options.  Verbose but what's new with getopt? */
-static void parse(int argc,
-		  char **argv,
-		  char **vmlinux,
-		  char ***object,
-		  int *objects,
-		  char **ksyms,
-		  char **lsmod,
-		  char **system_map,
-		  char **save_system_map,
-		  char ***filename,
-		  int *filecount,
-		  int *spec_h,
-		  int *code_bytes,
-		  int *one_shot
-		 )
-{
-	int spec_v = 0, spec_V = 0;
-	int spec_o = 0, spec_O = 0;
-	int spec_k = 0, spec_K = 0;
-	int spec_l = 0, spec_L = 0;
-	int spec_m = 0, spec_M = 0;
-	int spec_s = 0;
-	int spec_c = 0;
-
-	int c, i, some_spec = 0;
-	char *p;
-
-	while ((c = getopt(argc, argv, "v:Vo:Ok:Kl:Lm:Ms:dhc:1")) != EOF) {
-		if (debug && c != 'd')
-			fprintf(stderr, "DEBUG: getopt '%c' '%s'\n", c, optarg);
-		switch(c) {
-		case 'v':
-			*vmlinux = optarg;
-			++spec_v;
-			break;
-		case 'V':
-			*vmlinux = NULL;
-			++spec_V;
-			break;
-		case 'o':
-			if (!spec_o) {
-				/* First -o, discard default value(s) */
-				for (i = 0; i < *objects; ++i)
-					free((*object)[i]);
-				free(*object);
-				*object = NULL;
-				*objects = 0;
-			}
-			*object = realloc(*object,
-				((*objects)+1)*sizeof(**object));
-			if (!*object)
-				malloc_error("object");
-			if (!(p = strdup(optarg)))
-				malloc_error("strdup -o");
-			else {
-				(*object)[(*objects)++] = p;
-				++spec_o;
-			}
-			break;
-		case 'O':
-			++spec_O;
-			for (i = 0; i < *objects; ++i)
-				free((*object)[i]);
-			free(*object);
-			*object = NULL;
-			*objects = 0;
-			break;
-		case 'k':
-			*ksyms = optarg;
-			++spec_k;
-			break;
-		case 'K':
-			*ksyms = NULL;
-			++spec_K;
-			break;
-		case 'l':
-			*lsmod = optarg;
-			++spec_l;
-			break;
-		case 'L':
-			*lsmod = NULL;
-			++spec_L;
-			break;
-		case 'm':
-			*system_map = optarg;
-			++spec_m;
-			break;
-		case 'M':
-			*system_map = NULL;
-			++spec_M;
-			break;
-		case 's':
-			*save_system_map = optarg;
-			++spec_s;
-			break;
-		case 'd':
-			++debug;
-			break;
-		case 'h':
-			usage();
-			++*spec_h;
-			break;
-		case 'c':
-			++spec_c;
-			errno = 0;
-			*code_bytes = strtoul(optarg, &p, 10);
-			/* Oops_code_values assumes that code_bytes is a
-			 * multiple of 2.
-			 */
-			if (!*optarg || *p || errno ||
-				(*code_bytes != 1 &&
-				 *code_bytes != 2 &&
-				 *code_bytes != 4 &&
-				 *code_bytes != 8)) {
-				fprintf(stderr,
-					"%s Invalid value for -c '%s'\n",
-					prefix, optarg);
-				++errors;
-				if (errno)
-					perror(" ");
-				*code_bytes = DEF_CODE_BYTES;
-			}
-			break;
-		case '1':
-			*one_shot = !*one_shot;
-			break;
-		case '?':
-			usage();
-			exit(2);
-		}
-	}
-
-	*filecount = argc - optind;
-	*filename = argv + optind;
-
-	/* Expand any requests for the current uname values */
-	convert_uname(vmlinux);
-	if (*objects) {
-		for (i = 0; i < *objects; ++i)
-			convert_uname(*object+i);
-	}
-	convert_uname(ksyms);
-	convert_uname(lsmod);
-	convert_uname(system_map);
-
-	/* Check for multiple options specified */
-	multi_opt(spec_v, spec_V, 'v', *vmlinux);
-	multi_opt(spec_o, spec_O, 'o', *object ? **object : NULL);
-	multi_opt(spec_k, spec_K, 'k', *ksyms);
-	multi_opt(spec_l, spec_L, 'l', *lsmod);
-	multi_opt(spec_m, spec_M, 'm', *system_map);
-
-	printf("Options used:");
-	if (*vmlinux)
-		printf(" -v %s", *vmlinux);
-	else
-		printf(" -V");
-	spec_or_default(spec_v || spec_V, &some_spec);
-	
-	printf("             ");
-	if (*objects) {
-		for (i = 0; i < *objects; ++i)
-			printf(" -o %s", (*object)[i]);
-	}
-	else
-		printf(" -O");
-	spec_or_default(spec_o || spec_O, &some_spec);
-
-	printf("             ");
-	if (*ksyms)
-		printf(" -k %s", *ksyms);
-	else
-		printf(" -K");
-	spec_or_default(spec_k || spec_K, &some_spec);
-
-	printf("             ");
-	if (*lsmod)
-		printf(" -l %s", *lsmod);
-	else
-		printf(" -L");
-	spec_or_default(spec_l || spec_L, &some_spec);
-
-	printf("             ");
-	if (*system_map)
-		printf(" -m %s", *system_map);
-	else
-		printf(" -M");
-	spec_or_default(spec_m || spec_M, &some_spec);
-
-	printf("             ");
-	printf(" -c %d", *code_bytes);
-	spec_or_default(spec_c, NULL);
-
-	if (*one_shot) {
-		printf("             ");
-		printf(" -1");
-	}
-
-	printf("\n");
-
-	if (!some_spec) {
-		printf(
-"You did not tell me where to find symbol information.  I will assume\n"
-"that the log matches the kernel and modules that are running right now\n"
-"and I'll use the default options above for symbol resolution.\n"
-"If the current kernel and/or modules do not match the log, you can get\n"
-"more accurate output by telling me the kernel version and where to find\n"
-"map, modules, ksyms etc.  ksymoops -h explains the options.\n"
-			"\n");
-		++warnings;
-	}
-}
-
-/* Read environment variables */
-static void read_env(const char *external, char **internal)
-{
-	char *p;
-	if ((p = getenv(external))) {
-		*internal = p;
-		if (debug)
-			fprintf(stderr,
-				"DEBUG: env override %s=%s\n",
-				external, *internal);
-	}
-	else {
-		if (debug)
-			fprintf(stderr,
-				"DEBUG: env default %s=%s\n",
-				external, *internal);
-	}
-}
-
-
-int main(int argc, char **argv)
-{
-	char *vmlinux = NULL;
-	char **object = NULL;
-	int objects = 0;
-	char *ksyms = NULL;
-	char *lsmod = NULL;
-	char *system_map = NULL;
-	char *save_system_map = NULL;
-	char **filename;
-	int filecount = 0;
-	int spec_h = 0;		/* -h was specified */
-	int code_bytes = DEF_CODE_BYTES;
-	int one_shot = 0;
-	int i, ret;
-
-	prefix = *argv;
-	setvbuf(stdout, NULL, _IONBF, 0);
-
-#ifdef DEF_VMLINUX
-	vmlinux = DEF_LINUX;
-#endif
-#ifdef DEF_OBJECTS
-	{
-		char *p;
-		object = realloc(object, (objects+1)*sizeof(*object));
-		if (!object)
-			malloc_error("DEF_OBJECTS");
-		if (!(p = strdup(DEF_OBJECTS)))
-			malloc_error("DEF_OBJECTS");
-		else
-			object[objects++] = p;
-	}
-#endif
-#ifdef DEF_KSYMS
-	ksyms = DEF_KSYMS;
-#endif
-#ifdef DEF_LSMOD
-	lsmod = DEF_LSMOD;
-#endif
-#ifdef DEF_MAP
-	system_map = DEF_MAP;
-#endif
-
-	parse(argc,
-	      argv,
-	      &vmlinux,
-	      &object,
-	      &objects,
-	      &ksyms,
-	      &lsmod,
-	      &system_map,
-	      &save_system_map,
-	      &filename,
-	      &filecount,
-	      &spec_h,
-	      &code_bytes,
-	      &one_shot
-	     );
-
-	if (spec_h && filecount == 0)
-		return(0);	/* just the help text */
-
-	if (errors)
-		return(1);
-
-	if (debug)
-		fprintf(stderr, "DEBUG: level %d\n", debug);
-
-	read_env("KSYMOOPS_NM", &path_nm);
-	read_env("KSYMOOPS_FIND", &path_find);
-	read_env("KSYMOOPS_OBJDUMP", &path_objdump);
-
-	re_compile_common();
-	ss_init_common();
-
-	read_vmlinux(vmlinux);
-	read_ksyms(ksyms);
-	/* No point in reading modules unless ksyms shows modules loaded */
-	if (ss_ksyms_modules) {
-		expand_objects(object, objects);
-		for (i = 0; i < ss_objects; ++i)
-			read_object(ss_object[i].source, i);
-	}
-	else if (objects)
-		printf("No modules in ksyms, skipping objects\n");
-	/* No point in reading lsmod without ksyms */
-	if (ss_ksyms_modules || ss_ksyms_base.used)
-		read_lsmod(lsmod);
-	else if (lsmod)
-		printf("No ksyms, skipping lsmod\n");
-	read_system_map(system_map);
-	merge_maps(save_system_map);
-
-	/* After all that work, it is finally time to read the Oops report */
-	ret = Oops_read(filecount, filename, code_bytes, one_shot);
-
-	if (warnings || errors) {
-		printf("\n");
-		if (warnings)
-			printf("%d warning%s ",
-			       warnings, warnings == 1 ? "" : "s");
-		if (warnings && errors)
-			printf("and ");
-		if (errors)
-			printf("%d error%s ", errors, errors == 1 ? "" : "s");
-		printf("issued.  Results may not be reliable.\n");
-		if (!ret)
-			return(1);
-	}
-
-	return(ret);
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/ksymoops.h linux/scripts/ksymoops/ksymoops.h
--- v2.3.9/linux/scripts/ksymoops/ksymoops.h	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/ksymoops.h	Wed Dec 31 16:00:00 1969
@@ -1,146 +0,0 @@
-/*
-	ksymoops.h.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Read lsmod (/proc/modules).
-	Convert from a.out to bfd, using same format as ksymoops.
-	PPC trace addresses are not bracketed, add new re.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
-*/
-
-#include <sys/types.h>
-#include <regex.h>
-#include <stdio.h>
-
-
-/* Pity this is not externalised, see binfmt_elf.c */
-#define elf_addr_t unsigned long
-
-extern char *prefix;
-extern char *path_nm;		/* env KSYMOOPS_NM */
-extern char *path_find;		/* env KSYMOOPS_FIND */
-extern char *path_objdump;	/* env KSYMOOPS_OBJDUMP */
-extern int debug;
-extern int errors;
-extern int warnings;
-
-typedef struct symbol SYMBOL;
-
-struct symbol {
-	char *name;		/* name of symbol */
-	char type;		/* type of symbol from nm/System.map */
-	char keep;		/* keep this symbol in merged map? */
-	elf_addr_t address;	/* address in kernel */
-};
-
-/* Header for symbols from one particular source */
-
-typedef struct symbol_set SYMBOL_SET;
-
-struct symbol_set {
-	char *source;			/* where the symbols came from */
-	int used;			/* number of symbols used */
-	int alloc;			/* number of symbols allocated */
-	SYMBOL *symbol;			/* dynamic array of symbols */
-	SYMBOL_SET *related;		/* any related symbol set */
-};
-
-extern SYMBOL_SET  ss_vmlinux;
-extern SYMBOL_SET  ss_ksyms_base;
-extern SYMBOL_SET *ss_ksyms_module;
-extern int         ss_ksyms_modules;
-extern SYMBOL_SET  ss_lsmod;
-extern SYMBOL_SET *ss_object;
-extern int         ss_objects;
-extern SYMBOL_SET  ss_system_map;
-
-extern SYMBOL_SET  ss_merged;	/* merged map with info from all sources */
-extern SYMBOL_SET  ss_Version;	/* Version_ numbers where available */
-
-/* Regular expression stuff */
-
-extern regex_t     re_nm;
-extern regmatch_t *re_nm_pmatch;
-extern regex_t     re_bracketed_address;
-extern regmatch_t *re_bracketed_address_pmatch;
-extern regex_t     re_unbracketed_address;
-extern regmatch_t *re_unbracketed_address_pmatch;
-
-/* Bracketed address: optional '[', required '<', at least 4 hex characters,
- * required '>', optional ']', optional white space.
- */
-#define BRACKETED_ADDRESS	"\\[*<([0-9a-fA-F]{4,})>\\]*[ \t]*"
-
-#define UNBRACKETED_ADDRESS	"([0-9a-fA-F]{4,})[ \t]*"
-
-/* io.c */
-extern int regular_file(const char *file, const char *msg);
-extern FILE *fopen_local(const char *file, const char *mode, const char *msg);
-extern void fclose_local(FILE *f, const char *msg);
-extern char *fgets_local(char **line, int *size, FILE *f, const char *msg);
-extern int fwrite_local(void const *ptr, size_t size, size_t nmemb,
-			FILE *stream, const char *msg);
-extern FILE *popen_local(const char *cmd, const char *msg);
-extern void pclose_local(FILE *f, const char *msg);
-
-/* ksyms.c */
-extern void read_ksyms(const char *ksyms);
-extern void map_ksyms_to_modules(void);
-extern void read_lsmod(const char *lsmod);
-extern void compare_ksyms_lsmod(void);
-
-/* misc.c */
-extern void malloc_error(const char *msg);
-extern const char *format_address(elf_addr_t address);
-extern char *find_fullpath(const char *program);
-
-/* map.c */
-extern void read_system_map(const char *system_map);
-extern void merge_maps(const char *save_system_map);
-extern void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
-			 int precedence);
-
-
-/* object.c */
-extern SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss);
-extern void read_vmlinux(const char *vmlinux);
-extern void expand_objects(char * const *object, int objects);
-extern void read_object(const char *object, int i);
-
-/* oops.c */
-extern int Oops_read(int filecount, char * const *filename, int code_bytes,
-		     int one_shot);
-
-/* re.c */
-extern void re_compile(regex_t *preg, const char *regex, int cflags,
-		       regmatch_t **pmatch);
-extern void re_compile_common(void);
-extern void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
-		       char ***string);
-extern void re_strings_free(const regex_t *preg, char ***string);
-extern void re_string_check(int need, int available, const char *msg);
-
-/* symbol.c */
-extern void ss_init(SYMBOL_SET *ss, const char *msg);
-extern void ss_free(SYMBOL_SET *ss);
-extern void ss_init_common(void);
-extern SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol,
-				int *start);
-extern void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
-			 const char type, const char keep, const char *symbol);
-extern void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
-		       const char keep, const char *symbol);
-extern char *map_address(const SYMBOL_SET *ss, const elf_addr_t address);
-extern void ss_sort_atn(SYMBOL_SET *ss);
-extern void ss_sort_na(SYMBOL_SET *ss);
-extern SYMBOL_SET *ss_copy(const SYMBOL_SET *ss);
-extern void add_Version(const char *version, const char *source);
-extern void extract_Version(SYMBOL_SET *ss);
-extern void compare_Version(void);
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/ksyms.c linux/scripts/ksymoops/ksyms.c
--- v2.3.9/linux/scripts/ksymoops/ksyms.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/ksyms.c	Wed Dec 31 16:00:00 1969
@@ -1,294 +0,0 @@
-/*
-	ksyms.c.
-
-	Process ksyms for ksymoops.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Fri Nov  6 10:38:42 EST 1998
-	Version 0.6b
-	Remove false warnings when comparing ksyms and lsmod.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Read lsmod (/proc/modules).
-	Move "Using_Version" copy to map.c.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-
-/* Scan one line from ksyms.  Split lines into the base symbols and the module
- * symbols.  Separate ss for base and each module.
- */
-static void scan_ksyms_line(const char *line)
-{
-	int i;
-	char **string = NULL;
-	SYMBOL_SET *ssp;
-	static char *prev_module = NULL;
-	static regex_t     re_ksyms;
-	static regmatch_t *re_ksyms_pmatch;
-	static char const procname[] = "scan_ksyms_line";
-
-	/* ksyms: address, symbol, optional module */
-	re_compile(&re_ksyms,
-		"^([0-9a-fA-F]{4,}) +([^ \t]+)([ \t]+\\[([^ ]+)\\])?$",
-		REG_NEWLINE|REG_EXTENDED,
-		&re_ksyms_pmatch);
-
-	i = regexec(&re_ksyms, line,
-		    re_ksyms.re_nsub+1, re_ksyms_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i)
-		return;
-
-	/* string [1] - address, [2] - symbol, [3] - white space+module,
-	 * [4] - module.
-	 */
-	re_strings(&re_ksyms, line, re_ksyms_pmatch, &string);
-	if (string[4]) {
-		if (!prev_module || strcmp(prev_module, string[4])) {
-			/* start of a new module in ksyms */
-			++ss_ksyms_modules;
-			ss_ksyms_module = realloc(ss_ksyms_module,
-				ss_ksyms_modules*sizeof(*ss_ksyms_module));
-			if (!ss_ksyms_module)
-				malloc_error("realloc ss_ksyms_module");
-			ssp = ss_ksyms_module+ss_ksyms_modules-1;
-			ss_init(ssp, string[4]);
-			prev_module = strdup(string[4]);
-			if (!prev_module)
-				malloc_error("strdup prev_module");
-		}
-		ssp = ss_ksyms_module+ss_ksyms_modules-1;
-	}
-	else
-		ssp = &ss_ksyms_base;
-	add_symbol(ssp, string[1], ' ', 1, string[2]);
-	re_strings_free(&re_ksyms, &string);
-}
-
-/* Read the symbols from ksyms.  */
-void read_ksyms(const char *ksyms)
-{
-	FILE *f;
-	char *line = NULL;
-	int i, size;
-	static char const procname[] = "read_ksyms";
-
-	if (!ksyms)
-		return;
-	ss_init(&ss_ksyms_base, "ksyms_base");
-	if (debug)
-		fprintf(stderr, "DEBUG: %s %s\n", procname, ksyms);
-
-	if (!regular_file(ksyms, procname))
-		return;
-
-	if (!(f = fopen_local(ksyms, "r", procname)))
-		return;
-
-	while (fgets_local(&line, &size, f, procname))
-		scan_ksyms_line(line);
-
-	fclose_local(f, procname);
-	free(line);
-
-	for (i = 0; i < ss_ksyms_modules; ++i) {
-		ss_sort_na(ss_ksyms_module+i);
-		extract_Version(ss_ksyms_module+i);
-	}
-	if (ss_ksyms_base.used) {
-		ss_sort_na(&ss_ksyms_base);
-		extract_Version(&ss_ksyms_base);
-	}
-	else {
-		fprintf(stderr,
-			"Warning, no kernel symbols in ksyms, is %s a valid "
-			"ksyms file?\n",
-			ksyms);
-		++warnings;
-	}
-
-	if (debug > 1) {
-		for (i = 0; i < ss_ksyms_modules; ++i) {
-			fprintf(stderr,
-				"DEBUG: %s %s used %d out of %d entries\n",
-				procname,
-				ss_ksyms_module[i].source,
-				ss_ksyms_module[i].used,
-				ss_ksyms_module[i].alloc);
-		}
-		fprintf(stderr,
-			"DEBUG: %s %s used %d out of %d entries\n",
-			procname, ss_ksyms_base.source, ss_ksyms_base.used,
-			ss_ksyms_base.alloc);
-	}
-}
-
-/* Map each ksyms module entry to the corresponding object entry.  Tricky,
- * see the comments in the docs about needing a unique symbol in each
- * module.
- */
-static void map_ksym_to_module(SYMBOL_SET *ss)
-{
-	int i, j, matches;
-	char *name = NULL;
-
-	for (i = 0; i < ss->used; ++i) {
-		matches = 0;
-		for (j = 0; j < ss_objects; ++j) {
-			name = (ss->symbol)[i].name;
-			if (find_symbol_name(ss_object+j, name, NULL)) {
-				++matches;
-				ss->related = ss_object+j;
-			}
-		}
-		if (matches == 1)
-			break;		/* unique symbol over all objects */
-		ss->related = NULL;	/* keep looking */
-	}
-	if (!(ss->related)) {
-		fprintf(stderr,
-			"Warning: cannot match loaded module %s to any "
-			"module object.  Trace may not be reliable.\n",
-			ss->source);
-		++warnings;
-	}
-	else if (debug)
-		fprintf(stderr,
-			"DEBUG: ksyms %s matches to %s based on unique "
-			"symbol %s\n",
-			ss->source, ss->related->source, name);
-}
-
-/* Map all ksyms module entries to their corresponding objects */
-void map_ksyms_to_modules(void)
-{
-	int i;
-	SYMBOL_SET *ss, *ssc;
-
-	for (i = 0; i < ss_ksyms_modules; ++i) {
-		ss = ss_ksyms_module+i;
-		map_ksym_to_module(ss);
-		if (ss->related) {
-			ssc = adjust_object_offsets(ss);
-			compare_maps(ss, ssc, 1);
-		}
-	}
-}
-
-/* Read the modules from lsmod.  */
-void read_lsmod(const char *lsmod)
-{
-	FILE *f;
-	char *line = NULL;
-	int i, size;
-	char **string = NULL;
-	static regex_t     re_lsmod;
-	static regmatch_t *re_lsmod_pmatch;
-	static char const procname[] = "read_lsmod";
-
-	if (!lsmod)
-		return;
-	ss_init(&ss_lsmod, "lsmod");
-	if (debug)
-		fprintf(stderr, "DEBUG: %s %s\n", procname, lsmod);
-
-	if (!regular_file(lsmod, procname))
-		return;
-
-	if (!(f = fopen_local(lsmod, "r", procname)))
-		return;
-
-	/* lsmod: module, size, use count, optional used by */
-	re_compile(&re_lsmod,
-		"^"
-		"[ \t]*([^ \t]+)"				/* 1 module */
-		"[ \t]*([^ \t]+)"				/* 2 size */
-		"[ \t]*([^ \t]+)"				/* 3 count */
-		"[ \t]*(.*)"					/* 4 used by */
-		"$",
-		REG_NEWLINE|REG_EXTENDED,
-		&re_lsmod_pmatch);
-
-	while (fgets_local(&line, &size, f, procname)) {
-		i = regexec(&re_lsmod, line,
-			    re_lsmod.re_nsub+1, re_lsmod_pmatch, 0);
-		if (debug > 3)
-			fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-		if (i)
-			continue;
-		re_strings(&re_lsmod, line, re_lsmod_pmatch, &string);
-		add_symbol(&ss_lsmod, string[2], ' ', 1, string[1]);
-	}
-
-	fclose_local(f, procname);
-	free(line);
-	re_strings_free(&re_lsmod, &string);
-	if (ss_lsmod.used)
-		ss_sort_na(&ss_lsmod);
-	else {
-		fprintf(stderr,
-			"Warning, no symbols in lsmod, is %s a valid "
-			"lsmod file?\n",
-			lsmod);
-		++warnings;
-	}
-
-	if (debug > 1)
-		fprintf(stderr,
-			"DEBUG: %s %s used %d out of %d entries\n",
-			procname, ss_lsmod.source, ss_lsmod.used,
-			ss_lsmod.alloc);
-}
-
-/* Compare modules from ksyms against module list in lsmod and vice versa.
- * There is one ss_ for each ksyms module and a single ss_lsmod to cross
- * check.
- */
-void compare_ksyms_lsmod(void)
-{
-	int i, j;
-	SYMBOL_SET *ss;
-	SYMBOL *s;
-	static char const procname[] = "compare_ksyms_lsmod";
-
-	if (!(ss_lsmod.used && ss_ksyms_modules))
-		return;
-
-	s = ss_lsmod.symbol;
-	for (i = 0; i < ss_lsmod.used; ++i, ++s) {
-		for (j = 0; j < ss_ksyms_modules; ++j) {
-			ss = ss_ksyms_module+j;
-			if (strcmp(s->name, ss->source) == 0)
-				break;
-		}
-		if (j >= ss_ksyms_modules) {
-			fprintf(stderr,
-				"Warning in %s, module %s is in lsmod but not "
-				"in ksyms, probably no symbols exported\n",
-				procname, s->name);
-			++warnings;
-		}
-	}
-
-	for (i = 0; i < ss_ksyms_modules; ++i) {
-		ss = ss_ksyms_module+i;
-		if (!find_symbol_name(&ss_lsmod, ss->source, NULL)) {
-			fprintf(stderr,
-				"Error in %s, module %s is in ksyms but not "
-				"in lsmod\n",
-				procname, ss->source);
-			++errors;
-		}
-	}
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/map.c linux/scripts/ksymoops/map.c
--- v2.3.9/linux/scripts/ksymoops/map.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/map.c	Wed Dec 31 16:00:00 1969
@@ -1,251 +0,0 @@
-/*
-	map.c.
-
-	Read System.map for ksymoops, create merged System.map.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Remove addresses 0-4095 from merged map after writing new map.
-	Move "Using_Version" copy to map.c.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-
-/* Read the symbols from System.map */
-void read_system_map(const char *system_map)
-{
-	FILE *f;
-	char *line = NULL, **string = NULL;
-	int i, size = 0;
-	static char const procname[] = "read_system_map";
-
-	if (!system_map)
-		return;
-	ss_init(&ss_system_map, "System.map");
-	if (debug)
-		fprintf(stderr, "DEBUG: %s %s\n", procname, system_map);
-
-	if (!regular_file(system_map, procname))
-		return;
-
-	if (!(f = fopen_local(system_map, "r", procname)))
-		return;
-
-	while (fgets_local(&line, &size, f, procname)) {
-		i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
-		if (debug > 3)
-			fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-		if (i == 0) {
-			re_strings(&re_nm, line, re_nm_pmatch, &string);
-			add_symbol(&ss_system_map, string[1], *string[2],
-				   1, string[3]);
-		}
-	}
-
-	fclose_local(f, procname);
-	re_strings_free(&re_nm, &string);
-	free(line);
-	if (ss_system_map.used) {
-		ss_sort_na(&ss_system_map);
-		extract_Version(&ss_system_map);
-	}
-	else {
-		fprintf(stderr,
-			"Warning, no kernel symbols in System.map, is %s a "
-			"valid System.map file?\n",
-			system_map);
-		++warnings;
-	}
-
-	if (debug > 1)
-		fprintf(stderr,
-			"DEBUG: %s %s used %d out of %d entries\n",
-			procname,
-			ss_system_map.source,
-			ss_system_map.used,
-			ss_system_map.alloc);
-}
-
-/* Compare two maps, all symbols in the first should appear in the second. */
-void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
-			 int precedence)
-{
-	int i, start = 0;
-	SYMBOL *s1, *s2, **sdrop = precedence == 1 ? &s2 : &s1;
-	const SYMBOL_SET **ssdrop = precedence == 1 ? &ss2 : &ss1;
-
-	if (!(ss1->used && ss2->used))
-		return;
-
-	if (debug > 1)
-		fprintf(stderr,
-			"DEBUG: compare_maps %s vs %s, %s takes precedence\n",
-			ss1->source, ss2->source,
-			precedence == 1 ? ss1->source : ss2->source);
-
-	for (i = 0; i < ss1->used; ++i) {
-		s1 = ss1->symbol+i;
-		if (!(s1->keep))
-			continue;
-		s2 = find_symbol_name(ss2, s1->name, &start);
-		if (!s2) {
-			/* Some types only appear in nm output, not in things
-			 * like System.map.  Silently ignore them.
-			 */
-			if (s1->type == 'a' || s1->type == 't')
-				continue;
-			fprintf(stderr,
-				"Warning: %s symbol %s not found in %s.  "
-				"Ignoring %s entry\n",
-				ss1->source, s1->name,
-				ss2->source, (*ssdrop)->source);
-			++warnings;
-			if (*sdrop)
-				(*sdrop)->keep = 0;
-		}
-		else if (s1->address != s2->address) {
-			/* Type C symbols cannot be resolved from nm to ksyms,
-			 * silently ignore them.
-			 */
-			if (s1->type == 'C' || s2->type == 'C')
-				continue;
-			fprintf(stderr,
-				"Warning: mismatch on symbol %s %c, "
-				"%s says %lx, %s says %lx.  "
-				"Ignoring %s entry\n",
-				s1->name, s1->type, ss1->source, s1->address,
-				ss2->source, s2->address, (*ssdrop)->source);
-			++warnings;
-			if (*sdrop)
-				(*sdrop)->keep = 0;
-		}
-		else
-			++start;	/* step to next entry in ss2 */
-	}
-}
-
-/* Append the second symbol set onto the first */
-static void append_map(SYMBOL_SET *ss1, const SYMBOL_SET *ss2)
-{
-	int i;
-	SYMBOL *s;
-
-	if (!ss2 || !ss2->used)
-		return;
-	if (debug > 1)
-		fprintf(stderr, "DEBUG: append_map %s to %s\n",
-			ss2->source, ss1->source);
-
-	for (i = 0; i < ss2->used; ++i) {
-		s = ss2->symbol+i;
-		if (s->keep)
-			add_symbol_n(ss1, s->address, s->type, 1,
-				s->name);
-	}
-}
-
-/* Compare the various sources and build a merged system map */
-void merge_maps(const char *save_system_map)
-{
-	int i;
-	SYMBOL *s;
-	FILE *f;
-	static char const procname[] = "merge_maps";
-
-	if (debug)
-		fprintf(stderr, "DEBUG: %s\n", procname);
-
-	/* Using_Versions only appears in ksyms, copy to other tables */
-	if ((s = find_symbol_name(&ss_ksyms_base,
-			"Using_Versions", 0))) {
-		if (ss_system_map.used) {
-			add_symbol_n(&ss_system_map, s->address,
-				s->type, s->keep, s->name);
-			ss_sort_na(&ss_system_map);
-		}
-		if (ss_vmlinux.used) {
-			add_symbol_n(&ss_vmlinux, s->address, s->type,
-				s->keep, s->name);
-			ss_sort_na(&ss_vmlinux);
-		}
-	}
-
-	compare_Version();	/* highlight any version problems first */
-	compare_ksyms_lsmod();	/* highlight any missing modules next */
-	compare_maps(&ss_ksyms_base, &ss_vmlinux, 2);
-	compare_maps(&ss_system_map, &ss_vmlinux, 2);
-	compare_maps(&ss_vmlinux, &ss_system_map, 1);
-	compare_maps(&ss_ksyms_base, &ss_system_map, 2);
-
-	if (ss_objects) {
-		map_ksyms_to_modules();
-	}
-
-	ss_init(&ss_merged, "merged");
-	append_map(&ss_merged, &ss_vmlinux);
-	append_map(&ss_merged, &ss_ksyms_base);
-	append_map(&ss_merged, &ss_system_map);
-	for (i = 0; i < ss_ksyms_modules; ++i)
-		append_map(&ss_merged, (ss_ksyms_module+i)->related);
-	if (!ss_merged.used) {
-		fprintf(stderr, "Warning, no symbols in merged map\n");
-		++warnings;
-	}
-
-	/* drop duplicates, type a (registers) and gcc2_compiled. */
-	ss_sort_atn(&ss_merged);
-	s = ss_merged.symbol;
-	for (i = 0; i < ss_merged.used-1; ++i) {
-		if (s->type == 'a' ||
-		    (s->type == 't' && !strcmp(s->name, "gcc2_compiled.")))
-			s->keep = 0;
-		else if (strcmp(s->name, (s+1)->name) == 0 &&
-		    s->address == (s+1)->address) {
-			if (s->type != ' ')
-				(s+1)->keep = 0;
-			else
-				s->keep = 0;
-		}
-		++s;
-	}
-	ss_sort_atn(&ss_merged);	/* will remove dropped variables */
-
-	if (save_system_map) {
-		if (debug)
-			fprintf(stderr, "DEBUG: writing merged map to %s\n",
-				save_system_map);
-		if (!(f = fopen_local(save_system_map, "w", procname)))
-			return;
-		s = ss_merged.symbol;
-		for (i = 0; i < ss_merged.used; ++i) {
-			if (s->keep)
-				fprintf(f, "%s %c %s\n",
-					format_address(s->address),
-					s->type, s->name);
-			++s;
-		}
-	}
-
-	/* The merged map may contain symbols with an address of 0, e.g.
-	 * Using_Versions.  These give incorrect results for low addresses in
-	 * map_address, such addresses map to "Using_Versions+xxx".  Remove
-	 * any addresses below (arbitrary) 4096 from the merged map.  AFAIK,
-	 * Linux does not use the first page on any arch.
-	 */
-	for (i = 0; i < ss_merged.used; ++i) {
-		if ((ss_merged.symbol+i)->address < 4096)
-			(ss_merged.symbol+i)->keep = 0;
-		else
-			break;
-	}
-	if (i)
-		ss_sort_atn(&ss_merged);	/* remove dropped variables */
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/misc.c linux/scripts/ksymoops/misc.c
--- v2.3.9/linux/scripts/ksymoops/misc.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/misc.c	Wed Dec 31 16:00:00 1969
@@ -1,108 +0,0 @@
-/*
-	misc.c.
-
-	Miscellaneous routines for ksymoops.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Convert from a.out to bfd, using same format as ksymoops.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-void malloc_error(const char *msg)
-{
-	fprintf(stderr, "%s: fatal malloc error for %s\n", prefix, msg);
-	exit(2);
-}
-
-/* Format an address with the correct number of leading zeroes */
-const char *format_address(elf_addr_t address)
-{
-	/* Well oversized */
-	static char format[10], text[200];
-	if (!*format)
-		snprintf(format, sizeof(format), "%%0%dlx",
-			2*sizeof(address));
-	snprintf(text, sizeof(text), format, address);
-	return(text);
-}
-
-/* Find the full pathname of a program.  Code heavily based on
- * glibc-2.0.5/posix/execvp.c.
- */
-char *find_fullpath(const char *program)
-{
-	char *fullpath = NULL;
-	char *path, *p;
-	size_t len;
-	static const char procname[] = "find_fullpath";
-
-	/* Don't search when it contains a slash.  */
-	if (strchr(program, '/')) {
-		if (!(fullpath = strdup(program)))
-			malloc_error(procname);
-		if (debug > 1)
-			fprintf(stderr, "DEBUG: %s %s\n", procname, fullpath);
-		return(fullpath);
-	}
-
-	path = getenv ("PATH");
-	if (!path) {
-		/* There is no `PATH' in the environment.  The default search
-		   path is the current directory followed by the path `confstr'
-		   returns for `_CS_PATH'.
-		 */
-		len = confstr(_CS_PATH, (char *) NULL, 0);
-		if (!(path = malloc(1 + len)))
-			malloc_error(procname);
-		path[0] = ':';
-		confstr(_CS_PATH, path+1, len);
-	}
-
-	len = strlen(program) + 1;
-	if (!(fullpath = malloc(strlen(path) + len)))
-		malloc_error(procname);
-	p = path;
-	do {
-		path = p;
-		p = strchr(path, ':');
-		if (p == NULL)
-			p = strchr(path, '\0');
-
-		/* Two adjacent colons, or a colon at the beginning or the end
-		 * of `PATH' means to search the current directory.
-		 */
-		if (p == path)
-			memcpy(fullpath, program, len);
-		else {
-			/* Construct the pathname to try.  */
-			memcpy(fullpath, path, p - path);
-			fullpath[p - path] = '/';
-			memcpy(&fullpath[(p - path) + 1], program, len);
-		}
-
-		/* If we have execute access, assume this is the program. */
-		if (access(fullpath, X_OK) == 0) {
-			if (debug > 1)
-				fprintf(stderr, "DEBUG: %s %s\n",
-					procname, fullpath);
-			return(fullpath);
-		}
-	} while (*p++ != '\0');
-
-	fprintf(stderr, "Error: %s %s could not find executable %s\n",
-		prefix, procname, program);
-	++errors;
-	return(NULL);
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/object.c linux/scripts/ksymoops/object.c
--- v2.3.9/linux/scripts/ksymoops/object.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/object.c	Wed Dec 31 16:00:00 1969
@@ -1,230 +0,0 @@
-/*
-	object.c.
-
-	object handling routines for ksymoops.  Read modules, vmlinux, etc. 
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/* Extract all symbols definitions from an object using nm */
-static void read_nm_symbols(SYMBOL_SET *ss, const char *file)
-{
-	FILE *f;
-	char *cmd, *line = NULL, **string = NULL;
-	int i, size = 0;
-	static char const procname[] = "read_nm_symbols";
-
-	if (!regular_file(file, procname))
-		return;
-
-	cmd = malloc(strlen(path_nm)+strlen(file)+2);
-	if (!cmd)
-		malloc_error("nm command");
-	strcpy(cmd, path_nm);
-	strcat(cmd, " ");
-	strcat(cmd, file);
-	if (debug > 1)
-		fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
-	if (!(f = popen_local(cmd, procname)))
-		return;
-	free(cmd);
-
-	while (fgets_local(&line, &size, f, procname)) {
-		i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
-		if (debug > 3)
-			fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-		if (i == 0) {
-			re_strings(&re_nm, line, re_nm_pmatch, &string);
-			add_symbol(ss, string[1], *string[2], 1, string[3]);
-		}
-	}
-
-	pclose_local(f, procname);
-	re_strings_free(&re_nm, &string);
-	free(line);
-	if (debug > 1)
-		fprintf(stderr,
-			"DEBUG: %s %s used %d out of %d entries\n",
-			procname, ss->source, ss->used, ss->alloc);
-}
-
-/* Read the symbols from vmlinux */
-void read_vmlinux(const char *vmlinux)
-{
-	if (!vmlinux)
-		return;
-	ss_init(&ss_vmlinux, "vmlinux");
-	read_nm_symbols(&ss_vmlinux, vmlinux);
-	if (ss_vmlinux.used) {
-		ss_sort_na(&ss_vmlinux);
-		extract_Version(&ss_vmlinux);
-	}
-	else {
-		fprintf(stderr,
-			"Warning, no kernel symbols in vmlinux, is %s a valid "
-			"vmlinux file?\n",
-			vmlinux);
-		++warnings;
-	}
-}
-
-
-/* Read the symbols from one object (module) */
-void read_object(const char *object, int i)
-{
-	ss_init(ss_object+i, object);
-	read_nm_symbols(ss_object+i, object);
-	if ((ss_object+i)->used) {
-		ss_sort_na(ss_object+i);
-		extract_Version(ss_object+i);
-	}
-	else {
-		fprintf(stderr, "Warning, no symbols in %s\n", object);
-		++warnings;
-	}
-}
-
-/* Add a new entry to the list of objects */
-static void add_ss_object(const char *file)
-{
-	++ss_objects;
-	ss_object = realloc(ss_object, ss_objects*sizeof(*ss_object));
-	if (!ss_object)
-		malloc_error("realloc ss_object");
-	ss_init(ss_object+ss_objects-1, file);
-}
-
-/* Run a directory and its subdirectories, looking for *.o files */
-static void find_objects(const char *dir)
-{
-	FILE *f;
-	char *cmd, *line = NULL;
-	int size = 0, files = 0;
-	static char const procname[] = "find_objects";
-	static char const options[] = " -follow -name '*.o' -print";
-
-	cmd = malloc(strlen(path_find)+1+strlen(dir)+strlen(options)+1);
-	if (!cmd)
-		malloc_error("find command");
-	strcpy(cmd, path_find);
-	strcat(cmd, " ");
-	strcat(cmd, dir);
-	strcat(cmd, options);
-	if (debug > 1)
-		fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
-	if (!(f = popen_local(cmd, procname)))
-		return;
-	free(cmd);
-
-	while (fgets_local(&line, &size, f, procname)) {
-		if (debug > 1)
-			fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
-		add_ss_object(line);
-		++files;
-	}
-
-	pclose_local(f, procname);
-	if (!files) {
-		fprintf(stderr,
-			"Warning: no *.o files in %s.  "
-			"Is %s a valid module directory?\n",
-			dir, dir);
-		++warnings;
-	}
-}
-
-/* Take the user supplied list of objects which can include directories.
- * Expand directories into any *.o files.  The results are stored in
- * ss_object, leaving the user supplied options untouched.
- */
-void expand_objects(char * const *object, int objects)
-{
-	struct stat statbuf;
-	int i;
-	const char *file;
-	static char const procname[] = "expand_objects";
-
-	for (i = 0; i < objects; ++i) {
-		file = object[i];
-		if (debug > 1)
-			fprintf(stderr, "DEBUG: %s checking '%s' - ",
-				procname, file);
-		if (!stat(file, &statbuf) && S_ISDIR(statbuf.st_mode)) {
-			if (debug > 1)
-				fprintf(stderr, "directory, expanding\n");
-			find_objects(file);
-		}
-		else {
-			if (debug > 1)
-				fprintf(stderr, "not directory\n");
-			add_ss_object(file);
-		}
-	}
-}
-
-/* Map a symbol type to a section code. 0 - text, 1 - data, 2 - read only data,
- * 3 - C (cannot relocate), 4 - the rest.
- */
-static int section(char type)
-{
-	switch (type) {
-	case 'T':
-	case 't':
-		return 0;
-	case 'D':
-	case 'd':
-		return 1;
-	case 'R':
-	case 'r':
-		return 2;
-	case 'C':
-		return 3;
-	default:
-		return 4;
-	}
-}
-
-/* Given ksyms module data which has a related object, create a copy of the
- * object data, adjusting the offsets to match where the module was loaded.
- */
-SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss)
-{
-	int i;
-	elf_addr_t adjust[] = {0, 0, 0, 0, 0};
-	SYMBOL *sk, *so;
-	SYMBOL_SET *ssc;
-
-	if (debug > 1)
-		fprintf(stderr,
-			"DEBUG: adjust_object_offsets %s\n", ss->source);
-
-	ssc = ss_copy(ss->related);
-
-	/* For common symbols, calculate the adjustment */
-	for (i = 0; i < ss->used; ++i) {
-		sk = ss->symbol+i;
-		if ((so = find_symbol_name(ssc, sk->name, NULL)))
-			adjust[section(so->type)] = sk->address - so->address;
-	}
-	for (i = 0; i < ssc->used; ++i) {
-		so = ssc->symbol+i;
-		/* Type C does not relocate well, silently ignore */
-		if (so->type != 'C' && adjust[section(so->type)])
-			so->address += adjust[section(so->type)];
-		else
-			so->keep = 0;  /* do not merge into final map */
-	}
-
-	ss->related = ssc;	/* map using adjusted copy */
-	return(ssc);
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/oops.c linux/scripts/ksymoops/oops.c
--- v2.3.9/linux/scripts/ksymoops/oops.c	Thu Apr 22 19:24:52 1999
+++ linux/scripts/ksymoops/oops.c	Wed Dec 31 16:00:00 1969
@@ -1,1377 +0,0 @@
-/*
-	oops.c.
-
-	Oops processing for ksymoop.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-	
-	Sun Jan  7 12:56:12 CET 1999
-	Added SPARC64 support and some SPARC hacks by "Jakub Jelinek"
-	<jj@ultra.linux.cz>
-
-	Mon Jan  4 08:47:55 EST 1999
-	Version 0.6d
-	Add ARM support.
-
-	Thu Nov 26 16:37:46 EST 1998
-	Version 0.6c
-	Typo in oops_code.
-	Add -c option.
-
-	Tue Nov  3 23:33:04 EST 1998
-	Version 0.6a
-	Performance inprovements.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Oops file must be regular.
-	Add "invalid operand" to Oops_print.
-	Minor adjustment to re for ppc.
-	Minor adjustment to re for objdump lines with <_EIP+xxx>.
-	Convert from a.out to bfd, using same format as ksymoops.
-	Added MIPS.
-	PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into seperate sources.
- */
-
-#include "ksymoops.h"
-#include <bfd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <memory.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-enum oops_arch {
-	OOPS_NOARCH,
-	OOPS_I386,
-	OOPS_SPARC,
-	OOPS_SPARC64,
-	OOPS_ARM,
-	OOPS_ALPHA,
-	OOPS_MIPS,
-	OOPS_PPC,
-	OOPS_M68K
-} oops_arch;
-
-char *eip_names[] = { "IP", "EIP", "PC", "PC", "PC", "PC", "PC", "NIP", "PC" };
-
-/* Error detected by bfd */
-static void Oops_bfd_perror(const char *msg)
-{
-	fprintf(stderr, "Error ");
-	bfd_perror(msg);
-	++errors;
-}
-
-/* Safest way to get correct output bfd format is to copy ksymoops' format. */
-static int Oops_copy_bfd_format(bfd **ibfd, bfd **obfd, asection **isec,
-				const char *file)
-{
-	char *me, **matches, **match;
-
-	if (!(*obfd = bfd_openw(file, NULL))) {
-		Oops_bfd_perror(file);
-		return(0);
-	}
-
-	me = find_fullpath(prefix);
-	if (!me)
-		return(0);
-
-	if (!(*ibfd = bfd_openr(me, NULL))) {
-		Oops_bfd_perror(me);
-		return(0);
-	}
-	free(me);	/* Who is Tommy? */
-
-	if (!bfd_check_format_matches(*ibfd, bfd_object, &matches)) {
-		Oops_bfd_perror(me);
-		if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
-			fprintf(stderr, "Matching formats:");
-			match = matches;
-			while (*match)
-				fprintf(stderr, " %s", *match++);
-			fprintf(stderr, "\n");
-			free(matches);
-		}
-		return(0);
-	}
-
-	if (!(*isec = bfd_get_section_by_name(*ibfd, ".text"))) {
-		Oops_bfd_perror("get_section");
-		return(0);
-	}
-
-	bfd_set_format(*obfd, bfd_object);
-	bfd_set_arch_mach(*obfd, bfd_get_arch(*ibfd), bfd_get_mach(*ibfd));
-
-	if (!bfd_set_file_flags(*obfd, bfd_get_file_flags(*ibfd))) {
-		Oops_bfd_perror("set_file_flags");
-		return(0);
-	}
-
-	return(1);
-}
-
-/* Write the code values to a file using bfd. */
-static int Oops_write_bfd_data(bfd *ibfd, bfd *obfd, asection *isec,
-			       const char *code, int size)
-{
-	asection *osec;
-	asymbol *osym;
-
-	if (!bfd_set_start_address(obfd, 0)) {
-		Oops_bfd_perror("set_start_address");
-		return(0);
-	}
-	if (!(osec = bfd_make_section(obfd, ".text"))) {
-		Oops_bfd_perror("make_section");
-		return(0);
-	}
-	if (!bfd_set_section_flags(obfd, osec, 
-		bfd_get_section_flags(ibfd, isec))) {
-		Oops_bfd_perror("set_section_flags");
-		return(0);
-	}
-	if (!bfd_set_section_alignment(obfd, osec, 
-		bfd_get_section_alignment(ibfd, isec))) {
-		Oops_bfd_perror("set_section_alignment");
-		return(0);
-	}
-	osec->output_section = osec;
-	if (!(osym = bfd_make_empty_symbol(obfd))) {
-		Oops_bfd_perror("make_empty_symbol");
-		return(0);
-	}
-	osym->name = "_EIP";
-	osym->section = osec;
-	osym->flags = BSF_GLOBAL;
-	osym->value = 0;
-	if (!bfd_set_symtab(obfd, &osym, 1)) {
-		Oops_bfd_perror("set_symtab");
-		return(0);
-	}
-	if (!bfd_set_section_size(obfd, osec, size)) {
-		Oops_bfd_perror("set_section_size");
-		return(0);
-	}
-	if (!bfd_set_section_vma(obfd, osec, 0)) {
-		Oops_bfd_perror("set_section_vma");
-		return(0);
-	}
-	if (!bfd_set_section_contents(obfd, osec, (PTR) code, 0, size)) {
-		Oops_bfd_perror("set_section_contents");
-		return(0);
-	}
-	if (!bfd_close(obfd)) {
-		Oops_bfd_perror("close(obfd)");
-		return(0);
-	}
-	if (!bfd_close(ibfd)) {
-		Oops_bfd_perror("close(ibfd)");
-		return(0);
-	}
-	return 1;
-}
-
-/* Write the Oops code to a temporary file with suitable header and trailer. */
-static char *Oops_code_to_file(const char *code, int size)
-{
-	char *file;
-	bfd *ibfd, *obfd;
-	asection *isec;
-
-	bfd_init();
-	file = tmpnam(NULL);
-	if (!Oops_copy_bfd_format(&ibfd, &obfd, &isec, file))
-		return(NULL);
-	if (!Oops_write_bfd_data(ibfd, obfd, isec, code, size))
-		return(NULL);
-	return(file);
-}
-
-/* Run objdump against the binary Oops code */
-static FILE *Oops_objdump(const char *file)
-{
-	char *cmd;
-	FILE *f;
-	static char const options[] = "-dhf ";
-	static char const procname[] = "Oops_objdump";
-
-	cmd = malloc(strlen(path_objdump)+1+13+strlen(options)+strlen(file)+1);
-	if (!cmd)
-		malloc_error(procname);
-	strcpy(cmd, path_objdump);
-	strcat(cmd, " ");
-	if (oops_arch == OOPS_SPARC64)
-		strcat(cmd, "-m sparc:v9a ");
-	strcat(cmd, options);
-	strcat(cmd, file);
-	if (debug > 1)
-		fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
-	f = popen_local(cmd, procname);
-	free(cmd);
-	return(f);
-}
-
-/* Process one code line from objdump, ignore everything else */
-static void Oops_decode_one(SYMBOL_SET *ss, const char *line, elf_addr_t eip,
-			    int adjust)
-{
-	int i, j;
-	elf_addr_t address, eip_relative;
-	char *line2, *map, **string = NULL, *p;
-	static regex_t     re_Oops_objdump;
-	static regmatch_t *re_Oops_objdump_pmatch;
-	static char const procname[] = "Oops_decode_one";
-
-	/* objdump output.  Optional whitespace, hex digits, optional
-	 * ' <_EIP+offset>', ':'.  The '+offset' after _EIP is also optional.
-	 * Older binutils output 'xxxxxxxx <_EIP+offset>:', newer versions do
-	 * '00000000 <_EIP>:' first followed by '      xx:' lines.
-	 *
-	 * Just to complicate things even more, objdump recognises jmp, call,
-	 * etc., converts the code to something like this :-
-	 * "   f: e8 32 34 00 00  call   3446 <_EIP+0x3446>"
-	 * Recognise this and append the eip adjusted address, followed by the
-	 * map_address text for that address.
-	 *
-	 * With any luck, objdump will take care of all such references which
-	 * makes this routine architecture insensitive.  No need to test for
-	 * i386 jmp, call or m68k swl etc.
-	 */
-	re_compile(&re_Oops_objdump,
-			"^[ \t]*"
-			"([0-9a-fA-F]+)"				/* 1 */
-			"( <_EIP[^>]*>)?"				/* 2 */
-			":"
-			"("						/* 3 */
-			".* +"
-			"(0?x?[0-9a-fA-F]+ +)"				/* 4 */
-			"<_EIP\\+0?x?([0-9a-fA-F]+)>[ \t]*$"		/* 5 */
-			")?"
-			".*"
-			,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_objdump_pmatch);
-
-	i = regexec(&re_Oops_objdump, line, re_Oops_objdump.re_nsub+1,
-		re_Oops_objdump_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i != 0)
-		return;
-
-	re_strings(&re_Oops_objdump, line, re_Oops_objdump_pmatch, &string);
-	errno = 0;
-	address = strtoul(string[1], NULL, 16);
-	if (errno) {
-		fprintf(stderr,
-			"%s Invalid hex value in objdump line, "
-			"treated as zero - '%s'\n"
-			"  objdump line '%s'\n",
-			procname, string[1], line);
-		perror(" ");
-		++errors;
-		address = 0;
-	}
-	address += eip + adjust;
-	if (string[5]) {
-		/* EIP relative data to be adjusted */
-		errno = 0;
-		eip_relative = strtoul(string[5], NULL, 16);
-		if (errno) {
-#ifdef __sparc__
-			/* Try strtoull also, e.g. sparc binutils print <_PC+0xfffffffffffffd58> */
-			errno = 0;
-			eip_relative = strtoull(string[5], NULL, 16);
-#endif
-			if (errno) {
-				fprintf(stderr,
-					"%s Invalid hex value in objdump line, "
-					"treated as zero - '%s'\n"
-					"  objdump line '%s'\n",
-					procname, string[5], line);
-				perror(" ");
-				++errors;
-				eip_relative = 0;
-			}
-		}
-		eip_relative += eip + adjust;
-		map = map_address(&ss_merged, eip_relative);
-		/* new text is original line, eip_relative in hex, map text */
-		j = strlen(line);
-		if (string[4])
-			j = re_Oops_objdump_pmatch[4].rm_so;
-		i = j+1+2*sizeof(eip_relative)+1+strlen(map)+1;
-		line2 = malloc(i + 5);
-		if (!line2)
-			malloc_error(procname);
-		snprintf(line2, i, "%.*s %s %s",
-			j, line, format_address(eip_relative), map);
-	} else {
-		line2 = malloc(strlen(line) + 6);
-		if (!line2)
-			malloc_error(procname);
-		strcpy(line2, line);
-	}
-	if (oops_arch != OOPS_I386) {
-		p = line2;
-		while ((p = strstr(p, "_EIP"))) {
-			int l = strlen(eip_names[oops_arch]);
-			memcpy(p + 1, eip_names[oops_arch], l);
-			if (l < 3)
-				strcpy(p + 1 + l, p + 4);
-			p += 1 + l;
-		}
-	}
-	if (address == eip)
-		strcat(line2, " <===");			/* This makes it easier to locate visually the
-							   offending instruction */
-	add_symbol_n(ss, address, 'C', 1, line2);	/* as is */
-	free(line2);
-	re_strings_free(&re_Oops_objdump, &string);
-}
-
-/* Maximum number of code bytes to process.  It needs to be a multiple of 2 for
- * code_byte (-c) swapping.  Sparc and alpha dump 36 bytes so use 64.
- */
-#define CODE_SIZE 64
-
-/******************************************************************************/
-/*                     Start architecture sensitive code                      */
-/******************************************************************************/
-
-/* Extract the hex values from the Code: line and convert to binary */
-static int Oops_code_values(const unsigned char* code_text, char *code,
-			    int *adjust, char ***string, int string_max,
-			    int code_bytes)
-{
-	int byte = 0, i, l;
-	unsigned long c;
-	char *value;
-	const char *p;
-	static regex_t     re_Oops_code_value;
-	static regmatch_t *re_Oops_code_value_pmatch;
-	static const char procname[] = "Oops_code_values";
-
-	/* Given by re_Oops_code: code_text is a message (e.g. "general
-	 * protection") or one or more hex fields separated by space or tab.
-	 * Some architectures bracket the current instruction with '<'
-	 * and '>', others use '(' and ')'.  The first character is
-	 * nonblank.
-	 */
-	if (!isxdigit(*code_text)) {
-		fprintf(stderr,
-			"Warning, Code looks like message, not hex digits.  "
-			"No disassembly attempted.\n");
-		++warnings;
-		return(0);
-	}
-	memset(code, '\0', CODE_SIZE);
-	p = code_text;
-	*adjust = 0;	/* EIP points to code byte 0 */
-
-	/* Code values.  Hex values separated by white space.  On sparc, the
-	 * current instruction is bracketed in '<' and '>'.
-	 */
-	re_compile(&re_Oops_code_value,
-			"^"
-			"([<(]?)"					/* 1 */
-			"([0-9a-fA-F]+)"				/* 2 */
-			"[>)]?"
-			"[ \t]*"
-			,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_code_value_pmatch);
-
-	re_string_check(re_Oops_code_value.re_nsub+1, string_max, procname);
-	while (regexec(&re_Oops_code_value, p, re_Oops_code_value.re_nsub+1,
-			re_Oops_code_value_pmatch, 0) == 0) {
-		re_strings(&re_Oops_code_value, p,
-			re_Oops_code_value_pmatch, string);
-		if (byte >= CODE_SIZE)
-			break;
-		errno = 0;
-		value = (*string)[2];
-		c = strtoul(value, NULL, 16);
-		if (errno) {
-			fprintf(stderr,
-				"%s Invalid hex value in code_value line, "
-				"treated as zero - '%s'\n"
-				"  code_value line '%s'\n",
-				procname, value, code_text);
-			perror(" ");
-			++errors;
-			c = 0;
-		}
-		if ((*string)[1] && *((*string)[1]))
-			*adjust = -byte;	/* this byte is EIP */
-		/* i386 - 2 byte code, m68k - 4 byte, sparc - 8 byte.
-		 * On some architectures Code: is a stream of bytes, on some it
-		 * is a stream of shorts, on some it is a stream of ints.
-		 * Consistent we're not!
-		 */
-		l = strlen(value);
-		if (l%2) {
-			fprintf(stderr,
-				"%s invalid value 0x%s in Code line, not a "
-				"multiple of 2 digits, value ignored\n",
-				procname, value);
-			++errors;
-		}
-		else while (l) {
-			if (byte >= CODE_SIZE) {
-				fprintf(stderr,
-					"%s Warning: extra values in Code "
-					"line, ignored - '%s'\n",
-					procname, value);
-				++warnings;
-				break;
-			}
-			l -= 2;
-			code[byte++] = (c >> l*4) & 0xff;
-			value += 2;
-		}
-		p += re_Oops_code_value_pmatch[0].rm_eo;
-	}
-
-	if (*p) {
-		fprintf(stderr,
-			"Warning garbage '%s' at end of code line ignored "
-			"by %s\n",
-			p, procname);
-		++warnings;
-	}
-
-	/* The code_bytes parameter says how many readable bytes form a single
-	 * code unit in machine terms.  -c 1 says that the text is already in
-	 * machine order, -c 2 (4, 8) says each chunk of 2 (4, 8) bytes must be
-	 * swapped to get back to machine order.  Which end is up?
-	 */
-	if (code_bytes != 1) {
-		if (byte % code_bytes) {
-			fprintf(stderr,
-				"Warning: the number of code bytes (%d) is not "
-				"a multiple of -c (%d)\n"
-				"Byte swapping may not give sensible results\n",
-				byte, code_bytes);
-			++warnings;
-		}
-		for (l = 0; l < byte; l+= code_bytes) {
-			for (i = 0; i < code_bytes/2; ++i) {
-				c = code[l+i];
-				code[l+i] = code[l+code_bytes-i-1];
-				code[l+code_bytes-i-1] = c;
-			}
-		}
-	}
-
-	return(1);
-}
-
-/* Look for the EIP: line, returns start of the relevant hex value */
-static char *Oops_eip(const char *line, char ***string, int string_max)
-{
-	int i;
-	static regex_t     re_Oops_eip_sparc;
-	static regmatch_t *re_Oops_eip_sparc_pmatch;
-	static regex_t     re_Oops_eip_sparc64;
-	static regmatch_t *re_Oops_eip_sparc64_pmatch;
-	static regex_t     re_Oops_eip_ppc;
-	static regmatch_t *re_Oops_eip_ppc_pmatch;
-	static regex_t     re_Oops_eip_mips;
-	static regmatch_t *re_Oops_eip_mips_pmatch;
-	static regex_t     re_Oops_eip_other;
-	static regmatch_t *re_Oops_eip_other_pmatch;
-	static const char procname[] = "Oops_eip";
-	
-	/* Oops 'EIP:' line for sparc, actually PSR followed by PC */
-	re_compile(&re_Oops_eip_sparc,
-			"^PSR: [0-9a-fA-F]+ PC: " UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_eip_sparc_pmatch);
-
-	i = regexec(&re_Oops_eip_sparc, line, re_Oops_eip_sparc.re_nsub+1,
-		re_Oops_eip_sparc_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec sparc %d\n", procname, i);
-	if (i == 0) {
-		re_string_check(re_Oops_eip_sparc.re_nsub+1, string_max,
-			procname);
-		re_strings(&re_Oops_eip_sparc, line, re_Oops_eip_sparc_pmatch,
-			string);
-		oops_arch = OOPS_SPARC;
-		return((*string)[re_Oops_eip_sparc.re_nsub]);
-	}
-
-	/* Oops 'EIP:' line for sparc64, actually TSTATE followed by TPC */
-	re_compile(&re_Oops_eip_sparc64,
-			"^TSTATE: [0-9a-fA-F]{16} TPC: " UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_eip_sparc64_pmatch);
-
-	re_string_check(re_Oops_eip_sparc64.re_nsub+1, string_max, procname);
-	i = regexec(&re_Oops_eip_sparc64, line, re_Oops_eip_sparc64.re_nsub+1,
-		re_Oops_eip_sparc64_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec sparc64 %d\n", procname, i);
-	if (i == 0) {
-		re_strings(&re_Oops_eip_sparc64, line, re_Oops_eip_sparc64_pmatch,
-			string);
-		oops_arch = OOPS_SPARC64;
-		return((*string)[re_Oops_eip_sparc64.re_nsub]);
-	}
-
-	/* Oops 'EIP:' line for PPC, all over the place */
-	re_compile(&re_Oops_eip_ppc,
-			"("
-			  "(kernel pc )"
-			  "|(trap at PC: )"
-			  "|(bad area pc )"
-			  "|(NIP: )"
-			")"
-			UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_eip_ppc_pmatch);
-
-	i = regexec(&re_Oops_eip_ppc, line, re_Oops_eip_ppc.re_nsub+1,
-		re_Oops_eip_ppc_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec ppc %d\n", procname, i);
-	if (i == 0) {
-		re_string_check(re_Oops_eip_ppc.re_nsub+1, string_max,
-			procname);
-		re_strings(&re_Oops_eip_ppc, line, re_Oops_eip_ppc_pmatch,
-			string);
-		oops_arch = OOPS_PPC;
-		return((*string)[re_Oops_eip_ppc.re_nsub]);
-	}
-
-	/* Oops 'EIP:' line for MIPS, epc, optional white space, ':',
-	 * optional white space, unbracketed address.
-	 */
-	re_compile(&re_Oops_eip_mips,
-			"^(epc[ \t]*:+[ \t]*)"
-			UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_eip_mips_pmatch);
-
-	i = regexec(&re_Oops_eip_mips, line, re_Oops_eip_mips.re_nsub+1,
-		re_Oops_eip_mips_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec mips %d\n", procname, i);
-	if (i == 0) {
-		re_string_check(re_Oops_eip_mips.re_nsub+1, string_max,
-			procname);
-		re_strings(&re_Oops_eip_mips, line, re_Oops_eip_mips_pmatch,
-			string);
-		oops_arch = OOPS_MIPS;
-		return((*string)[re_Oops_eip_mips.re_nsub]);
-	}
-
-	/* Oops 'EIP:' line for other architectures */
-	re_compile(&re_Oops_eip_other,
-			"^("
-	/* i386 */	"(EIP:[ \t]+.*)"
-	/* m68k */	"|(PC[ \t]*=[ \t]*)"
-	/* ARM */	"|(pc *: *)"
-			")"
-			BRACKETED_ADDRESS
-			,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_eip_other_pmatch);
-
-	i = regexec(&re_Oops_eip_other, line, re_Oops_eip_other.re_nsub+1,
-		re_Oops_eip_other_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec other %d\n", procname, i);
-	if (i == 0) {
-		re_string_check(re_Oops_eip_other.re_nsub+1, string_max,
-			procname);
-		re_strings(&re_Oops_eip_other, line, re_Oops_eip_other_pmatch,
-			string);
-		oops_arch = OOPS_I386;
-		return((*string)[re_Oops_eip_other.re_nsub]);
-	}
-	return(NULL);
-}
-
-/* Set the eip from the EIP line */
-static void Oops_set_eip(const char *value, elf_addr_t *eip, SYMBOL_SET *ss)
-{
-	static const char procname[] = "Oops_set_eip";
-	char buf[10];
-	errno = 0;
-	*eip = strtoul(value, NULL, 16);
-	if (errno) {
-		fprintf(stderr,
-			"%s Invalid hex value in EIP line, ignored - '%s'\n",
-			procname, value);
-		perror(" ");
-		++errors;
-		*eip = 0;
-	}
-	sprintf(buf, ">>%s:", eip_names[oops_arch]);
-	add_symbol_n(ss, *eip, 'E', 1, buf);
-}
-
-/* Look for the MIPS ra line, returns start of the relevant hex value */
-static char *Oops_ra(const char *line, char ***string, int string_max)
-{
-	int i;
-	static regex_t     re_Oops_ra;
-	static regmatch_t *re_Oops_ra_pmatch;
-	static const char procname[] = "Oops_ra";
-
-	/* Oops 'ra:' line for MIPS, ra, optional white space, one or
-	 * more '=', optional white space, unbracketed address.
-	 */
-	re_compile(&re_Oops_ra,
-			"(ra[ \t]*=+[ \t]*)"
-			UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_ra_pmatch);
-
-	i = regexec(&re_Oops_ra, line, re_Oops_ra.re_nsub+1,
-		re_Oops_ra_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i == 0) {
-		re_string_check(re_Oops_ra.re_nsub+1, string_max, procname);
-		re_strings(&re_Oops_ra, line, re_Oops_ra_pmatch,
-			string);
-		return((*string)[re_Oops_ra.re_nsub]);
-	}
-	return(NULL);
-}
-
-/* Set the MIPS ra from the ra line */
-static void Oops_set_ra(const char *value, SYMBOL_SET *ss)
-{
-	static const char procname[] = "Oops_set_ra";
-	elf_addr_t ra;
-	errno = 0;
-	ra = strtoul(value, NULL, 16);
-	if (errno) {
-		fprintf(stderr,
-			"%s Invalid hex value in ra line, ignored - '%s'\n",
-			procname, value);
-		perror(" ");
-		++errors;
-		ra = 0;
-	}
-	add_symbol_n(ss, ra, 'R', 1, ">>RA :");
-}
-
-/* Look for the SPARC o7/i7 registers line, returns start of the relevant hex value */
-static char *Oops_oi7(const char *line, char ***string, int string_max)
-{
-	int i;
-	static regex_t     re_Oops_oi7;
-	static regmatch_t *re_Oops_oi7_pmatch;
-	static const char procname[] = "Oops_oi7";
-
-	re_compile(&re_Oops_oi7,
-			"^[io][04]: [0-9a-fA-F iosp:]+ ([io]7|ret_pc): "
-			UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_oi7_pmatch);
-
-	re_string_check(re_Oops_oi7.re_nsub+1, string_max, procname);
-	i = regexec(&re_Oops_oi7, line, re_Oops_oi7.re_nsub+1,
-		re_Oops_oi7_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i == 0) {
-		re_strings(&re_Oops_oi7, line, re_Oops_oi7_pmatch,
-			string);
-		return((*string)[re_Oops_oi7.re_nsub]);
-	}
-	return(NULL);
-}
-
-/* Set the SPARC o7/i7 from the oi7 line */
-static void Oops_set_oi7(const char *value, char ***string, SYMBOL_SET *ss)
-{
-	static const char procname[] = "Oops_set_oi7";
-	elf_addr_t oi7;
-	int o7 = 1;
-	errno = 0;
-	oi7 = strtoul(value, NULL, 16);
-	if ((*string)[1] && !strcmp((*string)[1], "i7"))
-		o7 = 0;
-	if (errno) {
-		fprintf(stderr,
-			"%s Invalid hex value in oi7 line, ignored - '%s'\n",
-			procname, value);
-		perror(" ");
-		++errors;
-		oi7 = 0;
-	}
-	add_symbol_n(ss, oi7, 'O', 1, o7 ? ">>O7:" : ">>I7:");
-}
-
-/* Look for the SPARC register dump lines end */
-static int Oops_sparc_regdump(const char *line)
-{
-	int i;
-	static regex_t     re_Oops_sparc_regdump;
-	static regmatch_t *re_Oops_sparc_regdump_pmatch;
-	static const char procname[] = "Oops_sparc_regdump";
-
-	re_compile(&re_Oops_sparc_regdump,
-		       "^(i[04]: "
-			"|Instruction DUMP: "
-			"|Caller\\["
-			")",
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_sparc_regdump_pmatch);
-
-	i = regexec(&re_Oops_sparc_regdump, line, re_Oops_sparc_regdump.re_nsub+1,
-		re_Oops_sparc_regdump_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i == 0)
-		return 1;
-	return 0;
-}
-
-
-/* Look for the Trace multilines :(.  Returns start of addresses. */
-static const char *Oops_trace(const char *line, char ***string, int string_max)
-{
-	int i;
-	const char *start = NULL;
-	static int trace_line = 0;
-	static regex_t     re_Oops_trace;
-	static regmatch_t *re_Oops_trace_pmatch;
-	static const char procname[] = "Oops_trace";
-
-	/* ppc is different, not a bracketed address, just an address */
-	/* ARM is different, two bracketed addresses on each line */
-
-	/* Oops 'Trace' lines */
-	re_compile(&re_Oops_trace,
-			"^("					/*  1 */
-			"(Call Trace: )"			/*  2 */
-	/* alpha */	"|(Trace: )"				/*  3 */
-	/* various */	"|(" BRACKETED_ADDRESS ")"	   	/* 4,5*/
-	/* ppc */	"|(Call backtrace:)"			/*  6 */
-	/* ppc */	"|(" UNBRACKETED_ADDRESS ")"		/* 7,8*/
-	/* ARM */	"|(Function entered at (" BRACKETED_ADDRESS "))"	/* 9,10,11 */
-	/* sparc */
-	/* sparc64 */	"|(Caller\\[" UNBRACKETED_ADDRESS "\\])"/*12,13*/
-			")",
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_trace_pmatch);
-
-	i = regexec(&re_Oops_trace, line, re_Oops_trace.re_nsub+1,
-		re_Oops_trace_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i == 0) {
-#undef MATCHED
-#define MATCHED(n) (re_Oops_trace_pmatch[n].rm_so != -1)
-		if (MATCHED(2) || MATCHED(3)) {
-			trace_line = 1;
-			start = line + re_Oops_trace_pmatch[0].rm_eo;
-		}
-		else if (MATCHED(6)) {
-			trace_line = 2;		/* ppc */
-			start = line + re_Oops_trace_pmatch[0].rm_eo;
-		}
-		else if (trace_line == 1 && MATCHED(5))
-			start = line + re_Oops_trace_pmatch[5].rm_so;
-		else if (trace_line == 2 && MATCHED(8))	/* ppc */
-			start = line + re_Oops_trace_pmatch[8].rm_so;
-		else if (MATCHED(10)){
-			trace_line = 1;		/* ARM */
-			start = line + re_Oops_trace_pmatch[10].rm_so;
-		} else if (MATCHED(12)) {
-			trace_line = 0;		/* sparc, sparc64 */
-			start = line + re_Oops_trace_pmatch[13].rm_so;
-			return start;
-		} else
-			trace_line = 0;
-	}
-	else
-		trace_line = 0;
-	if (trace_line)
-		return(start);
-	return(NULL);
-}
-
-/* Process a trace call line, extract addresses */
-static void Oops_trace_line(const char *line, const char *p, SYMBOL_SET *ss)
-{
-	char **string = NULL;
-	regex_t *pregex;
-	regmatch_t *pregmatch;
-	static const char procname[] = "Oops_trace_line";
-
-	/* ppc does not bracket its addresses */
-	if (isxdigit(*p)) {
-		pregex = &re_unbracketed_address;
-		pregmatch = re_unbracketed_address_pmatch;
-	}
-	else {
-		pregex = &re_bracketed_address;
-		pregmatch = re_bracketed_address_pmatch;
-	}
-
-	/* Loop over [un]?bracketed addresses */
-	while (1) {
-		if (regexec(pregex, p, pregex->re_nsub+1, pregmatch, 0) == 0) {
-			re_strings(pregex, p, pregmatch, &string);
-			add_symbol(ss, string[1], 'T', 1, "Trace:");
-			p += pregmatch[0].rm_eo;
-		}
-		else if (strncmp(p, "from ", 5) == 0)
-			p += 5;		/* ARM does "address from address" */
-		else
-			break;
-	}
-
-	if (*p && !strcmp(p, "...")) {
-		fprintf(stderr,
-			"Warning garbage '%s' at end of trace line ignored "
-			"by %s\n",
-			p, procname);
-		++warnings;
-	}
-	re_strings_free(pregex, &string);
-}
-
-/* Do pattern matching to decide if the line should be printed.  When reading a
- * syslog containing multiple Oops, you need the intermediate data (registers,
- * tss etc.) to go with the decoded text.  Sets text to the start of the useful
- * text, after any prefix.  Note that any leading white space is treated as part
- * of the prefix, later routines do not see any indentation.
- *
- * Note: If a line is not printed, it will not be scanned for any other text.
- */
-static int Oops_print(const char *line, const char **text, char ***string,
-		      int string_max)
-{
-	int i, print = 0;
-	static int stack_line = 0, trace_line = 0;
-	static regex_t     re_Oops_prefix;
-	static regmatch_t *re_Oops_prefix_pmatch;
-	static regex_t     re_Oops_print_s;
-	static regmatch_t *re_Oops_print_s_pmatch;
-	static regex_t     re_Oops_print_a;
-	static regmatch_t *re_Oops_print_a_pmatch;
-	static const char procname[] = "Oops_print";
-
-	*text = line;
-
-	/* Lines to be ignored.  For some reason the "amuse the user" print in
-	 * some die_if_kernel routines causes regexec to run very slowly.
-	 */
-
-	if (strstr(*text, "\\|/ ____ \\|/")  ||
-	    strstr(*text, "\"@'/ ,. \\`@\"") ||
-	    strstr(*text, "/_| \\__/ |_\\")  ||
-	    strstr(*text, "   \\__U_/"))
-		return(1);	/* print but avoid regexec */
-
-	/* Prefixes to be ignored */
-	re_compile(&re_Oops_prefix,
-			"^("			/* start of line */
-			"([^ ]{3} [ 0-9][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} "
-			  "[^ ]+ kernel: +)"	/* syslogd */
-			"|(<[0-9]+>)"		/* kmsg */
-			"|([ \t]+)"		/* leading white space */
-			")+"			/* any prefixes, in any order */
-			,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_prefix_pmatch);
-
-	i = regexec(&re_Oops_prefix, *text, re_Oops_prefix.re_nsub+1,
-		re_Oops_prefix_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec prefix %d\n", procname, i);
-	if (i == 0)
-		*text += re_Oops_prefix_pmatch[0].rm_eo;  /* step over prefix */
-
-
-	/* Lots of possibilities.  Expand as required for all architectures.
-	 *
-	 * Trial and error shows that regex does not like a lot of sub patterns
-	 * that start with "^".  So split the patterns into two groups, one set
-	 * must appear at the start of the line, the other set can appear
-	 * anywhere.
-	 */
-
-	/* These patterns must appear at the start of the line, after stripping
-	 * the prefix above.
-	 *
-	 * The order below is required to handle multiline outupt.
-	 * string 2 is defined if the text is 'Stack from '.
-	 * string 3 is defined if the text is 'Stack: '.
-	 * string 4 is defined if the text might be a stack continuation.
-	 * string 5 is defined if the text is 'Call Trace: '.
-	 * string 6 is defined if the text might be a trace continuation.
-	 * string 7 is the address part of the BRACKETED_ADDRESS.
-	 *
-	 * string 8 is defined if the text contains a version number.  No Oops
-	 * report contains this as of 2.1.125 but IMHO it should be added.  If
-	 * anybody wants to print a VERSION_nnnn line in their Oops, this code
-	 * is ready.
-	 *
-	 * string 9 is defined if the text is 'Trace: ' (alpha).
-	 * string 10 is defined if the text is 'Call backtrace:' (ppc).
-	 */
-	re_compile(&re_Oops_print_s,
-       /* arch type */					    /* Required order */
-			"^("						/*  1 */
-	/* i386 */	"(Stack: )"					/*  2 */
-	/* m68k */	"|(Stack from )"				/*  3 */
-	/* various */	"|([0-9a-fA-F]{4,})"				/*  4 */
-	/* various */	"|(Call Trace: )"				/*  5 */
-	/* various */	"|(" BRACKETED_ADDRESS ")"			/* 6,7*/
-	/* various */	"|(Version_[0-9]+)"				/*  8 */
-	/* alpha */	"|(Trace: )"					/*  9 */
-	/* ppc */	"|(Call backtrace:)"				/* 10 */
-
-			/* order does not matter from here on */
-	
-	/* various */	"|(Process .*stackpage=)"
-	/* various */	"|(Call Trace:[ \t])"
-	/* various */	"|(Code *:[ \t])"
-	/* various */	"|(Kernel panic)"
-	/* various */	"|(In swapper task)"
-
-	/* i386 2.0 */	"|(Corrupted stack page)"
-	/* i386 */	"|(invalid operand: )"
-	/* i386 */	"|(Oops: )"
-	/* i386 */	"|(Cpu: +[0-9])"
-	/* i386 */	"|(current->tss)"
-	/* i386 */	"|(\\*pde +=)"
-	/* i386 */	"|(EIP: )"
-	/* i386 */	"|(EFLAGS: )"
-	/* i386 */	"|(eax: )"
-	/* i386 */	"|(esi: )"
-	/* i386 */	"|(ds: )"
-
-	/* m68k */	"|(pc[:=])"
-	/* m68k */	"|(68060 access)"
-	/* m68k */	"|(Exception at )"
-	/* m68k */	"|(d[04]: )"
-	/* m68k */	"|(Frame format=)"
-	/* m68k */	"|(wb [0-9] stat)"
-	/* m68k */	"|(push data: )"
-	/* m68k */	"|(baddr=)"
-	/* any other m68K lines to print? */
-
-	/* alpha */	"|(Bad unaligned kernel)"
-	/* alpha */	"|(Forwarding unaligned exception)"
-	/* alpha */	"|(: unhandled unaligned exception)"
-	/* alpha */	"|(<sc)"
-	/* alpha */	"|(pc *=)"
-	/* alpha */	"|(r[0-9]+ *=)"
-	/* alpha */	"|(gp *=)"
-	/* any other alpha lines to print? */
-
-	/* sparc */	"|(tsk->)"
-	/* sparc */	"|(PSR: )"
-	/* sparc */	"|([goli][04]: )"
-	/* sparc */	"|(Instruction DUMP: )"
-	/* sparc */	"|(Caller\\[)"
-	/* any other sparc lines to print? */
-	
-	/* sparc64 */	"|(TSTATE: )"
-	/* any other sparc64 lines to print? */
-
-	/* ppc */	"|(MSR: )"
-	/* ppc */	"|(TASK = )"
-	/* ppc */	"|(last math )"
-	/* ppc */	"|(GPR[0-9]+: )"
-	/* any other ppc lines to print? */
-
-	/* MIPS */	"|(\\$[0-9 ]+:)"
-	/* MIPS */	"|(epc )"
-	/* MIPS */	"|(Status:)"
-	/* MIPS */	"|(Cause :)"
-	/* any other MIPS lines to print? */
-
-	/* ARM */	"|(Backtrace:)"
-	/* ARM */	"|(Function entered at)"
-	/* ARM */	"|(\\*pgd =)"
-	/* ARM */	"|(Internal error)"
-	/* ARM */	"|(pc :)"
-	/* ARM */	"|(sp :)"
-	/* ARM */	"|(r[0-9][0-9 ]:)"
-	/* ARM */	"|(Flags:)"
-	/* ARM */	"|(Control:)"
-	/* any other ARM lines to print? */
-
-			")",
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_print_s_pmatch);
-
-	i = regexec(&re_Oops_print_s, *text, re_Oops_print_s.re_nsub+1,
-		re_Oops_print_s_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec start %d\n", procname, i);
-	print = 0;
-	if (i == 0) {
-#undef MATCHED
-#define MATCHED(n) (re_Oops_print_s_pmatch[n].rm_so != -1)
-		print = 1;
-		/* Handle multiline messages, messy */
-		if (!MATCHED(2) && !MATCHED(3) && !MATCHED(4))
-			stack_line = 0;
-		else if (MATCHED(2) || MATCHED(3))
-			stack_line = 1;
-		else if (stack_line && !MATCHED(4)) {
-			print = 0;
-			stack_line = 0;
-		}
-		if (!MATCHED(5) && !MATCHED(6) && !MATCHED(9) && !MATCHED(10))
-			trace_line = 0;
-		else if (MATCHED(5) || MATCHED(9) || MATCHED(10))
-			trace_line = 1;
-		else if (stack_line && !MATCHED(6)) {
-			print = 0;
-			trace_line = 0;
-		}
-		/* delay splitting into strings until we really them */
-		if (MATCHED(8)) {
-			re_string_check(re_Oops_print_s.re_nsub+1, string_max,
-				procname);
-			re_strings(&re_Oops_print_s, *text,
-				re_Oops_print_s_pmatch,
-				string);
-			add_Version((*string)[8]+8, "Oops");
-		}
-	}
-
-	/* These patterns can appear anywhere in the line, after stripping
-	 * the prefix above.
-	 */
-	re_compile(&re_Oops_print_a,
-       /* arch type */
-
-	/* various */	"(Unable to handle kernel)"
-	/* various */	"|(Aiee)"      /* anywhere in text is a bad sign (TM) */
-	/* various */	"|(die_if_kernel)"	/* ditto */
-
-	/* alpha */	"|(\\([0-9]\\): Oops )"
-	/* alpha */	"|(: memory violation)"
-	/* alpha */	"|(: Exception at)"
-	/* alpha */	"|(: Arithmetic fault)"
-	/* alpha */	"|(: Instruction fault)"
-	/* alpha */	"|(: arithmetic trap)"
-	/* alpha */	"|(: unaligned trap)"
-
-	/* sparc      die_if_kernel has no fixed text, identify by (pid): text.
-	 *            Somebody has been playful with the texts.
-	 *
-	 *            Alas adding this next pattern increases run time by 15% on
-	 *            its own!  It would be considerably faster if sparc had
-	 *            consistent error texts.
-	 */
-	/* sparc */	"|("
-			   "\\([0-9]+\\): "
-			   "("
-			     "(Whee)"
-			     "|(Oops)"
-			     "|(Kernel)"
-			     "|(Penguin)"
-			     "|(Too many Penguin)"
-			     "|(BOGUS)"
-			   ")"
-			 ")"
-
-	/* ppc */	"|(kernel pc )"
-	/* ppc */	"|(trap at PC: )"
-	/* ppc */	"|(bad area pc )"
-	/* ppc */	"|(NIP: )"
-
-	/* MIPS */	"|( ra *=)"
-
-			")",
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_print_a_pmatch);
-
-	i = regexec(&re_Oops_print_a, *text, re_Oops_print_a.re_nsub+1,
-		re_Oops_print_a_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec anywhere %d\n", procname, i);
-	if (i == 0)
-		print = 1;
-
-	return(print);
-}
-
-/* Look for the Code: line.  Returns start of the code bytes. */
-static const char *Oops_code(const char *line, char ***string, int string_max)
-{
-	int i;
-	static regex_t     re_Oops_code;
-	static regmatch_t *re_Oops_code_pmatch;
-	static const char procname[] = "Oops_code";
-
-	/* Oops 'Code: ' hopefully followed by at least one hex code.  sparc
-	 * brackets the PC in '<' and '>'.  ARM brackets the PC in '(' and ')'.
-	 */
-	re_compile(&re_Oops_code,
-			"^("						/*  1 */
-	/* sparc */	  "(Instruction DUMP)"				/*  2 */
-	/* various */	  "|(Code *)"					/*  3 */
-			")"
-			":[ \t]+"
-			"("						/*  4 */
-			  "(general protection.*)"
-			  "|(<[0-9]+>)"
-			  "|(([<(]?[0-9a-fA-F]+[>)]?[ \t]+)+[<(]?[0-9a-fA-F]+[>)]?)"
-			")"
-			"(.*)$"				/* trailing garbage */
-			,
-		REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-		&re_Oops_code_pmatch);
-
-	i = regexec(&re_Oops_code, line, re_Oops_code.re_nsub+1,
-		re_Oops_code_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i == 0) {
-		re_string_check(re_Oops_code.re_nsub+1, string_max, procname);
-		re_strings(&re_Oops_code, line, re_Oops_code_pmatch,
-			string);
-		if ((*string)[re_Oops_code.re_nsub] &&
-		    *((*string)[re_Oops_code.re_nsub])) {
-			fprintf(stderr,
-				"Warning: trailing garbage ignored on Code: "
-				"line\n"
-				"  Text: '%s'\n"
-				"  Garbage: '%s'\n",
-				line, (*string)[re_Oops_code.re_nsub]);
-			++warnings;
-		}
-		return((*string)[4]);
-	}
-	return(NULL);
-}
-
-/******************************************************************************/
-/*                      End architecture sensitive code                       */
-/******************************************************************************/
-
-/* Decode the Oops Code: via objdump*/
-static void Oops_decode(const unsigned char* code_text, elf_addr_t eip,
-			SYMBOL_SET *ss, char ***string, int string_max,
-			int code_bytes)
-{
-	FILE *f;
-	char *file, *line = NULL, code[CODE_SIZE];
-	int size = 0, adjust;
-	static char const procname[] = "Oops_decode";
-
-	if (debug)
-		fprintf(stderr, "DEBUG: %s\n", procname);
-	/* text to binary */
-	if (!Oops_code_values(code_text, code, &adjust, string, string_max,
-		code_bytes))
-		return;
-	/* binary to same format as ksymoops */
-	if (!(file = Oops_code_to_file(code, CODE_SIZE)))
-		return;
-	/* objdump the pseudo object */
-	if (!(f = Oops_objdump(file)))	
-		return;
-	while (fgets_local(&line, &size, f, procname)) {
-		if (debug > 1)
-			fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
-		Oops_decode_one(ss, line, eip, adjust);
-	}
-	pclose_local(f, procname);	/* opened in Oops_objdump */
-	free(line);
-	if (unlink(file)) {
-		fprintf(stderr, "%s could not unlink %s", prefix, file);
-		perror(" ");
-	}
-}
-
-/* Reached the end of an Oops report, format the extracted data. */
-static void Oops_format(const SYMBOL_SET *ss_format)
-{
-	int i;
-	SYMBOL *s;
-	static const char procname[] = "Oops_format";
-
-	if (debug)
-		fprintf(stderr, "DEBUG: %s\n", procname);
-
-	compare_Version();	/* Oops might have a version one day */
-	printf("\n");
-	for (s = ss_format->symbol, i = 0; i < ss_format->used; ++i, ++s) {
-		/* For type C data, print Code:, address, map, "name" (actually
-		 * the text of an objdump line).  For other types print name,
-		 * address, map.
-		 */
-		if (s->type == 'C')
-			printf("Code:  %s %-30s %s\n",
-				format_address(s->address),
-				map_address(&ss_merged, s->address),
-				s->name);
-		else
-			printf("%s %s %s\n",
-				s->name,
-				format_address(s->address),
-				map_address(&ss_merged, s->address));
-	}
-	printf("\n");
-}
-
-/* Select next Oops input file */
-static FILE *Oops_next_file(int *filecount, char * const **filename)
-{
-	static FILE *f = NULL;
-	static const char procname[] = "Oops_next_file";
-	static int first_file = 1;
-
-	if (first_file) {
-		f = stdin;
-		first_file = 0;
-	}
-	while (*filecount) {
-		if (f)
-			fclose_local(f, procname);
-		f = NULL;
-		if (regular_file(**filename, procname))
-			f = fopen_local(**filename, "r", procname);
-		if (f) {
-			if (debug)
-				fprintf(stderr,
-					"DEBUG: reading Oops report "
-					"from %s\n", **filename);
-		}
-		++*filename;
-		--*filecount;
-		if (f)
-			return(f);
-	}
-	return(f);
-}
-
-/* Read the Oops report */
-#define MAX_STRINGS 300	/* Maximum strings in any Oops re */
-int Oops_read(int filecount, char * const *filename, int code_bytes,
-	      int one_shot)
-{
-	char *line = NULL, **string = NULL;
-	const char *start, *text;
-	int i, size = 0, lineno = 0, lastprint = 0, print = 0;
-	elf_addr_t eip = 0;
-	int sparc_regdump = 0;
-	FILE *f;
-	SYMBOL_SET ss_format;
-	static const char procname[] = "Oops_read";
-
-	ss_init(&ss_format, "Oops log data");
-
-	if (!filecount && isatty(0))
-		printf("Reading Oops report from the terminal\n");
-
-	string = malloc(MAX_STRINGS*sizeof(*string));
-	if (!string)
-		malloc_error(procname);
-	memset(string, '\0', MAX_STRINGS*sizeof(*string));
-
-	do {
-		if (!(f = Oops_next_file(&filecount, &filename)))
-			continue;
-		while (fgets_local(&line, &size, f, procname)) {
-			if (debug > 2)
-				fprintf(stderr,
-					"DEBUG: %s - %s\n", procname, line);
-			++lineno;
-			print = Oops_print(line, &text, &string, MAX_STRINGS);
-			if (Oops_sparc_regdump (text)) {
-				sparc_regdump = 1;
-			} else {
-				if ((oops_arch == OOPS_SPARC || 
-				     oops_arch == OOPS_SPARC64) &&
-				    sparc_regdump && ss_format.used) {
-					Oops_format(&ss_format);
-					ss_free(&ss_format);
-				}
-				sparc_regdump = 0;
-			}
-			if (print) {
-				puts(line);
-				lastprint = lineno;
-				if ((start = Oops_eip(text,
-					&string, MAX_STRINGS)))
-					Oops_set_eip(start, &eip, &ss_format);
-				if ((start = Oops_ra(text,
-					&string, MAX_STRINGS)))
-					Oops_set_ra(start, &ss_format);
-				if ((start = Oops_oi7(text,
-					&string, MAX_STRINGS)))
-					Oops_set_oi7(start, &string, 
-						&ss_format);
-				if ((start = Oops_trace(text,
-					&string, MAX_STRINGS)))
-					Oops_trace_line(text, start,
-						&ss_format);
-				if ((start = Oops_code(text,
-					&string, MAX_STRINGS))) {
-					Oops_decode(start, eip, &ss_format,
-						&string, MAX_STRINGS,
-						code_bytes);
-					Oops_format(&ss_format);
-					ss_free(&ss_format);
-					if (one_shot)
-						return(0);
-				}
-			}
-			/* More than 5 (arbitrary) lines which were not printed
-			 * and there is some saved data, assume we missed the
-			 * Code: line.
-			 */
-			if (ss_format.used && lineno > lastprint+5) {
-				fprintf(stderr,
-					"Warning, Code line not seen, dumping "
-					"what data is available\n");
-				++warnings;
-				Oops_format(&ss_format);
-				ss_free(&ss_format);
-				if (one_shot)
-					return(0);
-			}
-		}
-		if (ss_format.used) {
-			if ((oops_arch != OOPS_SPARC &&
-			     oops_arch != OOPS_SPARC64) || !sparc_regdump) {
-				fprintf(stderr,
-					"Warning, Code line not seen, dumping "
-					"what data is available\n");
-				++warnings;
-			}
-			Oops_format(&ss_format);
-			ss_free(&ss_format);
-			if (one_shot)
-				return(0);
-		}
-	} while (filecount != 0);
-
-	for (i = 0; i < sizeof(string); ++i) {
-		free(string[i]);
-		string[i] = NULL;
-	}
-	free(line);
-	if (one_shot)
-		return(3);	/* one shot mode, end of input, no data */
-	return(0);
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/re.c linux/scripts/ksymoops/re.c
--- v2.3.9/linux/scripts/ksymoops/re.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/re.c	Wed Dec 31 16:00:00 1969
@@ -1,145 +0,0 @@
-/*
-	re.c.
-
-	Regular expression processing for ksymoops.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	PPC trace addresses are not bracketed, add new re.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-
-/* Compile a regular expression */
-void re_compile(regex_t *preg, const char *regex, int cflags,
-		regmatch_t **pmatch)
-{
-	int i, l;
-	char *p;
-	static char const procname[] = "re_compile";
-
-	if (preg->re_nsub)
-		return;		/* already compiled */
-
-	if (debug)
-		fprintf(stderr, "DEBUG: %s '%s'", procname, regex);
-	if ((i = regcomp(preg, regex, cflags))) {
-		l = regerror(i, preg, NULL, 0);
-		++l;	/* doc is ambiguous, be safe */
-		p = malloc(l);
-		if (!p)
-			malloc_error("regerror text");
-		regerror(i, preg, p, l);
-		fprintf(stderr,
-			"%s: fatal %s error on '%s' - %s\n",
-			prefix, procname, regex, p);
-		exit(2);
-	}
-	if (debug)
-		fprintf(stderr, " %d sub expression(s)\n", preg->re_nsub);
-	/* [0] is entire match, [1] is first substring */
-	*pmatch = malloc((preg->re_nsub+1)*sizeof(**pmatch));
-	if (!*pmatch)
-		malloc_error("pmatch");
-
-}
-
-/* Compile common regular expressions */
-void re_compile_common(void)
-{
-
-	/* nm: address, type, symbol */
-	re_compile(&re_nm,
-		"^([0-9a-fA-F]{4,}) +([^ ]) +([^ ]+)$",
-		REG_NEWLINE|REG_EXTENDED,
-		&re_nm_pmatch);
-
-	/* bracketed address preceded by optional white space */
-	re_compile(&re_bracketed_address,
-		"^[ \t]*" BRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED,
-		&re_bracketed_address_pmatch);
-
-	/* unbracketed address preceded by optional white space */
-	re_compile(&re_unbracketed_address,
-		"^[ \t*]*" UNBRACKETED_ADDRESS,
-		REG_NEWLINE|REG_EXTENDED,
-		&re_unbracketed_address_pmatch);
-
-}
-
-/* Split text into the matching re substrings - Perl is so much easier :).
- * Each element of *string is set to a malloced copy of the substring or
- * NULL if the substring did not match (undef).  A zero length substring match
- * is represented by a zero length **string.
- */
-void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
-		char ***string)
-{
-	int i;
-	if (!*string) {
-		*string = malloc((preg->re_nsub+1)*sizeof(**string));
-		if (!*string)
-			malloc_error("re_strings base");
-		for (i = 0; i < preg->re_nsub+1; ++i)
-			(*string)[i] = NULL;
-	}
-	for (i = 0; i < preg->re_nsub+1; ++i) {
-		if (debug > 4)
-			fprintf(stderr,
-				"DEBUG: re_string %d offsets %d %d",
-				i, pmatch[i].rm_so, pmatch[i].rm_eo);
-		if (pmatch[i].rm_so == -1) {
-			/* no match for this sub expression */
-			free((*string)[i]);
-			(*string)[i] = NULL;
-			if (debug > 4)
-				fprintf(stderr, " (undef)\n");
-		}
-		else {
-			int l = pmatch[i].rm_eo - pmatch[i].rm_so + 1;
-			char *p;
-			p = malloc(l);
-			if (!p)
-				malloc_error("re_strings");
-			strncpy(p, text+pmatch[i].rm_so, l-1);
-			*(p+l-1) = '\0';
-			(*string)[i] = p;
-			if (debug > 4)
-				fprintf(stderr, " '%s'\n", p);
-		}
-	}
-}
-
-/* Free the matching re substrings */
-void re_strings_free(const regex_t *preg, char ***string)
-{
-	if (*string) {
-		int i;
-		for (i = 0; i < preg->re_nsub+1; ++i)
-			free((*string)[i]);
-		free(*string);
-		*string = NULL;
-	}
-}
-
-/* Check that there are enough strings for an re */
-void re_string_check(int need, int available, const char *msg)
-{
-	if (need > available) {
-		fprintf(stderr,
-			"%s: fatal not enough re_strings in %s.  "
-			"Need %d, available %d\n",
-			prefix, msg, need, available);
-		exit(2);
-	}
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ksymoops/symbol.c linux/scripts/ksymoops/symbol.c
--- v2.3.9/linux/scripts/ksymoops/symbol.c	Tue Jan  5 11:13:56 1999
+++ linux/scripts/ksymoops/symbol.c	Wed Dec 31 16:00:00 1969
@@ -1,444 +0,0 @@
-/*
-	symbol.c.
-
-	Symbol handling routines for ksymoops.
-
-	Copyright Keith Owens <kaos@ocs.com.au>.
-	Released under the GNU Public Licence, Version 2.
-
-	Mon Jan  4 09:08:19 EST 1999
-	Version 0.6d
-	Cast Version to int, glibc 2.1 made elf_addr_t a long.
-
-	Tue Nov  3 02:31:01 EST 1998
-	Version 0.6
-	Fix end of code calculation.
-
-	Wed Oct 28 13:47:23 EST 1998
-	Version 0.4
-	Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Initialise a symbol source */
-void ss_init(SYMBOL_SET *ss, const char *msg)
-{
-	memset(ss, '\0', sizeof(*ss));
-	ss->source = strdup(msg);
-	if (!ss->source)
-		malloc_error(msg);
-}
-
-/* Free dynamic data from a symbol source */
-void ss_free(SYMBOL_SET *ss)
-{
-	int i;
-	SYMBOL *s;
-	for (s = ss->symbol, i = 0; i < ss->used; ++i, ++s)
-		free(s->name);
-	free(ss->symbol);
-	free(ss->source);
-	memset(ss, '\0', sizeof(*ss));
-}
-
-/* Initialise common symbol sets */
-void ss_init_common(void)
-{
-	ss_init(&ss_Version, "Version_");
-}
-
-/* Find a symbol name in a symbol source.  Brute force ascending order search,
- * no hashing.  If start is not NULL, it contains the starting point for the
- * scan and is updated to point to the found entry.  If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by name.
- */
-SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol, int *start)
-{
-	int i, l;
-	SYMBOL *s;
-	for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
-		if ((l = strcmp(symbol, s->name)) == 0) {
-			if (start)
-				*start = i;
-			return(s);
-		}
-		if (l < 0)
-			break;
-	}
-	if (start)
-		*start = i;
-	return NULL;
-}
-
-/* Find an address in a symbol source.  Brute force ascending order search, no
- * hashing.  If start is not NULL, it contains the starting point for the scan
- * and is updated to point to the found entry.  If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by address.
- */
-static SYMBOL *find_symbol_address(const SYMBOL_SET *ss,
-			    const elf_addr_t address, int *start)
-{
-	int i;
-	SYMBOL *s;
-	for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
-		if (address > s->address)
-			continue;
-		else if (address == s->address) {
-			if (start)
-				*start = i;
-			return(s);
-		}
-		else
-			break;
-	}
-	if (start)
-		*start = i;
-	return NULL;
-}
-
-/* Add a symbol to a symbol set, address in binary */
-void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
-		  const char type, const char keep, const char *symbol)
-{
-	int i;
-	char **string = NULL;
-	SYMBOL *s;
-	static regex_t     re_symbol_ver;
-	static regmatch_t *re_symbol_ver_pmatch;
-	static const char procname[] = "add_symbol_n";
-
-	/* Strip out any trailing symbol version _Rxxxxxxxx. */
-	re_compile(&re_symbol_ver,
-		"^(.*)_R[0-9a-fA-F]{8,}$",
-		REG_NEWLINE|REG_EXTENDED,
-		&re_symbol_ver_pmatch);
-
-	i = regexec(&re_symbol_ver, symbol,
-		    re_symbol_ver.re_nsub+1, re_symbol_ver_pmatch, 0);
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-	if (i == 0)
-		re_strings(&re_symbol_ver, symbol, re_symbol_ver_pmatch,
-			&string);
-
-	if (debug > 3)
-		fprintf(stderr, "DEBUG: %s %s %s '%c' %d '%s'\n",
-			procname, ss->source, format_address(address),
-			type, keep, i == 0 ? string[1] : symbol);
-	if (ss->used > ss->alloc) {
-		fprintf(stderr,
-			"%s: fatal %s ss %s used (%d) > alloc (%d)\n",
-			procname, prefix, ss->source, ss->used, ss->alloc);
-		exit(2);
-	}
-	if (ss->used == ss->alloc) {
-		/* increase by 20% or 10, whichever is larger, arbitrary */
-		int newsize = ss->alloc*120/100;
-		if (newsize < ss->alloc+10)
-			newsize = ss->alloc+10;
-		if (debug > 3)
-			fprintf(stderr,
-				"DEBUG: %s increasing %s from %d to %d "
-				"entries\n",
-				procname, ss->source, ss->alloc, newsize);
-		ss->symbol = realloc(ss->symbol, newsize*sizeof(*(ss->symbol)));
-		if (!ss->symbol)
-			malloc_error("realloc ss");
-		ss->alloc = newsize;
-	}
-	s = ss->symbol+ss->used;
-	if (i == 0) {
-		s->name = string[1];
-		string[1] = NULL;	/* don't free this one */
-	}
-	else {
-		s->name = strdup(symbol);
-		if (!s->name)
-			malloc_error("strdup symbol");
-	}
-	s->type = type;
-	s->keep = keep;
-	s->address = address;
-	++ss->used;
-	re_strings_free(&re_symbol_ver, &string);
-}
-
-/* Add a symbol to a symbol set, address in character */
-void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
-		const char keep, const char *symbol)
-{
-	elf_addr_t a;
-	static char const procname[] = "add_symbol";
-	errno = 0;
-	a = strtoul(address, NULL, 16);
-	if (errno) {
-		fprintf(stderr,
-			"%s: %s address '%s' is in error",
-			prefix, procname, address);
-		perror(" ");
-		++errors;
-	}
-	add_symbol_n(ss, a, type, 1, symbol);
-}
-
-/* Map an address to symbol, offset and length, address in binary */
-char *map_address(const SYMBOL_SET *ss, const elf_addr_t address)
-{
-	int i = 0, l;
-	SYMBOL *s;
-	static char *map = NULL;
-	static int size = 0;
-	static const char procname[] = "map_address_n";
-
-	if (debug > 2)
-		fprintf(stderr, "DEBUG: %s %s %s\n",
-			procname, ss->source, format_address(address));
-	s = find_symbol_address(ss, address, &i);
-	if (!s && --i >= 0)
-		s = ss->symbol+i;	/* address is between s and s+1 */
-			
-	/* Extra map text is always < 100 bytes */
-	if (s)
-		l = strlen(s->name) + 100;
-	else
-		l = 100;
-	if (l > size) {
-		map = realloc(map, l);
-		if (!map)
-			malloc_error(procname);
-		size = l;
-	}
-	if (!s) {
-		if (ss->used == 0)
-			snprintf(map, size, "No symbols available");
-		else
-			snprintf(map, size, "Before first symbol");
-	}
-	else if ((i+1) >= ss->used) {
-		/* Somewhere past last symbol.  Length of last section of code
-		 * is unknown, arbitrary cutoff at 32K.
-		 */
-		elf_addr_t offset = address - s->address;
-		if (offset > 32768)
-			snprintf(map, size, "<END_OF_CODE+%lx/????>", offset);
-		else
-			snprintf(map, size, "<%s+%lx/????>", s->name, offset);
-	}
-	else
-		snprintf(map, size,
-			"<%s+%lx/%lx>",
-			s->name, address - s->address,
-			(s+1)->address - s->address);
-	return(map);
-}
-
-/* After sorting, obsolete symbols are at the top.  Delete them. */
-static void ss_compress(SYMBOL_SET *ss)
-{
-	int i, j;
-	SYMBOL *s;
-	static const char procname[] = "ss_compress";
-
-	if (debug > 1)
-		fprintf(stderr, "DEBUG: %s on table %s, before %d ",
-			procname, ss->source, ss->used);
-	for (i = 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
-		if (!s->keep) {
-			for (j = i; j < ss->used; ++j, ++s) {
-				if (s->keep) {
-					fprintf(stderr,
-						"%s: fatal %s table %s is not "
-						"sorted\n",
-						prefix, procname, ss->source);
-					exit(2);
-				}
-			}
-			break;
-		}
-	}
-	for (j = i, s = ss->symbol+j; j < ss->used; ++j, ++s)
-		free(s->name);
-	ss->used = i;
-	if (debug > 1)
-		fprintf(stderr, "after %d\n", ss->used);
-}
-
-static int ss_compare_atn(const void *a, const void *b)
-{
-	SYMBOL *c = (SYMBOL *) a;
-	SYMBOL *d = (SYMBOL *) b;
-	int i;
-
-	/* obsolete symbols to the top */
-	if (c->keep != d->keep)
-		return(d->keep - c->keep);
-	if (c->address > d->address)
-		return(1);
-	if (c->address < d->address)
-		return(-1);
-	if (c->type > d->type)
-		return(1);
-	if (c->type < d->type)
-		return(-1);
-	if ((i = strcmp(c->name, d->name)))
-		return(i);
-	return(0);
-}
-
-/* Sort a symbol set by address, type and name */
-void ss_sort_atn(SYMBOL_SET *ss)
-{
-	if (debug)
-		fprintf(stderr, "DEBUG: sorting symbols for %s (atn)\n",
-			ss->source);
-	qsort((char *) ss->symbol, (unsigned) ss->used,
-		sizeof(*(ss->symbol)), ss_compare_atn);
-	ss_compress(ss);
-}
-
-static int ss_compare_na(const void *a, const void *b)
-{
-	SYMBOL *c = (SYMBOL *) a;
-	SYMBOL *d = (SYMBOL *) b;
-	int i;
-
-	/* obsolete symbols to the top */
-	if (c->keep != d->keep)
-		return(d->keep - c->keep);
-	if ((i = strcmp(c->name, d->name)))
-		return(i);
-	if (c->address > d->address)
-		return(1);
-	if (c->address < d->address)
-		return(-1);
-	return(0);
-}
-
-/* Sort a symbol set by name and address, drop duplicates.  There should be
- * no duplicates but I have seen duplicates in ksyms on 2.0.35.
- */
-void ss_sort_na(SYMBOL_SET *ss)
-{
-	int i;
-	SYMBOL *s;
-	if (debug)
-		fprintf(stderr, "DEBUG: sorting symbols for %s (na)\n",
-			ss->source);
-	qsort((char *) ss->symbol, (unsigned) ss->used,
-		sizeof(*(ss->symbol)), ss_compare_na);
-	ss_compress(ss);
-	s = ss->symbol;
-	for (i = 0; i < ss->used-1; ++i) {
-		if (strcmp(s->name, (s+1)->name) == 0 &&
-		    s->address == (s+1)->address) {
-			if (s->type != ' ')
-				(s+1)->keep = 0;
-			else
-				s->keep = 0;
-		}
-		++s;
-	}
-	qsort((char *) ss->symbol, (unsigned) ss->used,
-		sizeof(*(ss->symbol)), ss_compare_na);
-	ss_compress(ss);
-}
-
-/* Copy a symbol set, including all its strings */
-SYMBOL_SET *ss_copy(const SYMBOL_SET *ss)
-{
-	SYMBOL_SET *ssc;
-	if (debug > 3)
-		fprintf(stderr,
-			"DEBUG: ss_copy %s\n", ss->source);
-	ssc = malloc(sizeof(*ssc));
-	if (!ssc)
-		malloc_error("copy ssc");
-	ss_init(ssc, ss->source);
-	ssc->used = ss->used;
-	ssc->alloc = ss->used;	/* shrink the copy */
-	ssc->symbol = malloc(ssc->used*sizeof(*(ssc->symbol)));
-	if (!(ssc->symbol))
-		malloc_error("copy ssc symbols");
-	memcpy(ssc->symbol, ss->symbol, ssc->used*sizeof(*(ssc->symbol)));
-	return(ssc);
-}
-
-/* Convert version number to major, minor string.  */
-static const char *format_Version(elf_addr_t Version)
-{
-	static char string[12];	/* 255.255.255\0 worst case */
-	snprintf(string, sizeof(string), "%d.%d.%d",
-		(int) ((Version >> 16) & 0xff),
-		(int) ((Version >> 8) & 0xff),
-		(int) ((Version) & 0xff));
-	return(string);
-}
-
-/* Save version number.  The "address" is the version number, the "symbol" is
- * the source of the version.
- */
-void add_Version(const char *version, const char *source)
-{
-	static char const procname[] = "add_Version";
-	int i = atoi(version);
-	if (debug > 1)
-		fprintf(stderr, "DEBUG: %s %s %s %s\n",
-			procname, source, version, format_Version(i));
-	add_symbol_n(&ss_Version, i, 'V', 1, source);
-}
-
-/* Extract Version_ number from a symbol set and save it.  */
-void extract_Version(SYMBOL_SET *ss)
-{
-	int i = 0;
-	SYMBOL *s;
-
-	s = find_symbol_name(ss, "Version_", &i);
-	if (!s && i < ss->used)
-		s = ss->symbol+i;	/* first symbol after "Version_" */
-	if (!s || strncmp(s->name, "Version_", 8))
-		return;
-	add_Version(s->name+8, ss->source);
-}
-
-/* Compare all extracted Version numbers.  Silent unless there is a problem. */
-void compare_Version(void)
-{
-	int i = 0;
-	SYMBOL *s, *s0;
-	static int prev_used = 0;
-
-	if (!ss_Version.used)
-		return;
-	/* Only check if the Version table has changed in size */
-	if (prev_used == ss_Version.used)
-		return;
-
-	ss_sort_na(&ss_Version);
-	s0 = s = ss_Version.symbol;
-	if (debug)
-		fprintf(stderr, "DEBUG: Version %s\n",
-			format_Version(s0->address));
-	for (i = 0; i < ss_Version.used; ++i, ++s) {
-		if (s->address != s0->address) {
-			fprintf(stderr,
-				"Version mismatch error.  %s says %s, ",
-				s0->name,
-				format_Version(s0->address));
-			fprintf(stderr,
-				"%s says %s.  Expect lots of address "
-				"mismatches.\n",
-				s->name,
-				format_Version(s->address));
-			++errors;
-		}
-	}
-	prev_used = ss_Version.used;
-}
diff -u --recursive --new-file v2.3.9/linux/scripts/ver_linux linux/scripts/ver_linux
--- v2.3.9/linux/scripts/ver_linux	Fri Apr 16 08:20:23 1999
+++ linux/scripts/ver_linux	Mon Jul  5 20:49:52 1999
@@ -21,10 +21,12 @@
 ps --version 2>&1 | awk 'NR==1{print "Procps                ", $NF}'
 mount --version | awk -F\- '{print "Mount                 ", $NF}'
 hostname -V 2>&1 | awk 'NR==1{print "Net-tools             ", $NF}'
+# Kbd needs 'loadkeys -h',
 loadkeys -h 2>&1 | awk \
-'(NR==1 && $3) {ver=$3}
- (NR==2 && $1 ~ /console-tools/) {print "Console-tools         ",$3; done=1}
- END {if (!done) print "Kbd                   ",ver}'
+'(NR==1 && ($3 !~ /option/)) {print "Kbd                   ", $3}'
+# while console-tools needs 'loadkeys -V'.
+loadkeys -V 2>&1 | awk \
+'(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools         ", $3}'
 expr --v | awk '{print "Sh-utils              ", $NF}'
 X=`cat /proc/modules | sed -e "s/ .*$//"`
 echo "Modules Loaded         "$X
