diff -u --recursive --new-file v2.3.49/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.49/linux/Documentation/Configure.help	Thu Mar  2 14:36:22 2000
+++ linux/Documentation/Configure.help	Mon Mar  6 15:49:21 2000
@@ -644,7 +644,7 @@
 Various ATA, Work(s) In Progress (EXPERIMENTAL)
 CONFIG_IDEDMA_PCI_WIP
   If you enable this you will be capable of using and testing
-  highly developmentail projects.
+  highly developmental projects.
 
   It is SAFEST to say N to this question.
 
@@ -2268,10 +2268,11 @@
      UMC U5D or U5S.
    - "586" for generic Pentium CPUs, possibly lacking the TSC 
      (time stamp counter) register.
-   - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and 
-     K6-3D.
+   - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5.
    - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
      Intel Pentium II/Pentium Pro.
+   - "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D).
+   - "Athlon" for the AMD Athlon (aka K7)
 
   If you don't know what to do, choose "386".
 
@@ -5990,7 +5991,8 @@
 	adhoc=1  	there are no Access Points around
 	master=1 	Adhoc master (the one who creates network sync)
 	slave=1		Adhoc slave(btw, it is still forming own net 
-			sometimes)
+			sometimes, and has problems with firmware...
+			change IbssJoinNetTimeout from /proc...)
 	channel=1..? 	meaningful in adhoc mode
   all other parameters can be set via /proc interface
   These parameters belong to .._card module, but alas, they are here
@@ -8411,7 +8413,7 @@
   
 USB-UHCI High Bandwidth support
 CONFIG_USB_UHCI_HIGH_BANDWIDTH
-  This option enables the so called reclamation loop in usb-uhci, thus
+  This option enables the so-called reclamation loop in usb-uhci, thus
   allowing much higher transfer bandwidth for USB-bulk and control
   messages; isochronous transfers (audio, video etc.) are not affected.
   Due to a very simple design of the UHCI controller, this may cause
@@ -8563,9 +8565,9 @@
 USB Serial converter support
 CONFIG_USB_SERIAL
   Say Y here if you want to connect a Connect Tech WhiteHEAT 
-  multi-port USB to serial converter; a Belkin, Peracom, or eTek
-  single port USB to serial converter; or a Handspring Visor.
-  Please read Documentation/usb/usb-serial.txt for more information.
+  multi-port USB to serial converter; a FTDI or Keyspan single port 
+  USB to serial converter; or a Handspring Visor. Please read 
+  Documentation/usb/usb-serial.txt for more information.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -8590,6 +8592,16 @@
   its USB docking station. See http://usbvisor.sourceforge.net for
   more information on using this driver.
 
+USB FTDI Single Port Serial Driver
+CONFIG_USB_SERIAL_FTDI_SIO
+  Say Y here if you want to use a FTDI SIO single port USB to serial
+  converter device.
+
+USB FTDI Single Port Serial Driver
+CONFIG_USB_SERIAL_KEYSPAN_PDA
+  Say Y here if you want to use a Keyspan PDA single port USB to serial
+  converter device.
+
 USB Printer support
 CONFIG_USB_PRINTER
   Say Y here if you want to connect a USB printer to your computer's USB
@@ -8651,16 +8663,17 @@
   The module will be called ov511.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-USB ADMtek's Pegasus based ethernet devices support
+USB ADMtek Pegasus-based ethernet device support
 CONFIG_USB_PEGASUS
-  Say Y if you want to use your usb ethernet device. Note that
-  the code is still experimental. If you have devices with other
-  vendor IDs than ADMtek's you should change/add them in the
+  Say Y if you want to use your USB ethernet device. Note that
+  the code is still experimental. If you have devices with vendor
+  IDs other than ADMtek's, you should change/add them in the
   driver code and send a message to me (petkan@spct.net) for 
   update.
+
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called ov511.o. If you want to compile it as a
+  The module will be called pegasus.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
 USB Kodak DC-2xx Camera support
@@ -8742,9 +8755,9 @@
  
 PLUSB driver
 CONFIG_USB_PLUSB
-  A driver for the Prolific PL-2302 USB to USB network device. This 'USB
-  cable' connects two hosts via a point to point network with bandwidth of
-  5Mbit/s.  Configure this driver after connecting the USB cable via
+  A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB
+  cable' connects two hosts via a point-to-point network with bandwidth of
+  5 Mbit/s.  Configure this driver after connecting the USB cable via
   ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 
   (and vice versa on the other host).
 
diff -u --recursive --new-file v2.3.49/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.3.49/linux/Documentation/filesystems/devfs/ChangeLog	Sun Feb 20 21:12:38 2000
+++ linux/Documentation/filesystems/devfs/ChangeLog	Tue Mar  7 11:07:42 2000
@@ -1463,3 +1463,20 @@
 - Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled
 
 - Fixed drivers/char/stallion.c
+===============================================================================
+Changes for patch v161
+
+Work sponsored by SGI
+
+- Remove /dev/ide when ide-mod is unloaded
+
+- Fixed bug in drivers/block/ide-probe.c when secondary but no primary
+
+- Added DEVFS_FL_NO_PERSISTENCE flag
+
+- Used new DEVFS_FL_NO_PERSISTENCE flag for Unix98 pty slaves
+
+- Removed unnecessary call to <update_devfs_inode_from_entry> in
+  <devfs_readdir>
+
+- Only set auto-ownership for /dev/pty/s*
diff -u --recursive --new-file v2.3.49/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.3.49/linux/Documentation/filesystems/devfs/README	Sun Feb 20 21:12:38 2000
+++ linux/Documentation/filesystems/devfs/README	Tue Mar  7 11:07:42 2000
@@ -4,7 +4,7 @@
 
 		Richard Gooch <rgooch@atnf.csiro.au>
 
-			      11-NOV-1999
+			      3-MAR-2000
 
 
 Conventions used in this document                                     <section>
@@ -22,6 +22,9 @@
 find out more about it at:
 http://www.atnf.csiro.au/~rgooch/linux/
 
+NEWFLASH: The official 2.3.46 kernel has included the devfs
+patch. Future patches will be released which build on this.
+
 
 What is it?                                                           <section>
 ===========
@@ -128,14 +131,13 @@
 There is an existing programme called scsidev which will automatically
 create device nodes for SCSI devices. It can do this by scanning files
 in /proc/scsi. Unfortunately, to extend this idea to other device
-nodes would require would require significant modifications to
-existing drivers (so they too would provide information in
-/proc). This is a non-trivial change (I should know: devfs has had to
-do something similar). Once you go to this much effort, you may as
-well use devfs itself (which also provides this information).
-Furthermore, such a system would likely be implemented in an ad-hoc
-fashion, as different drivers will provide their information in
-different ways.
+nodes would require significant modifications to existing drivers (so
+they too would provide information in /proc). This is a non-trivial
+change (I should know: devfs has had to do something similar). Once
+you go to this much effort, you may as well use devfs itself (which
+also provides this information).  Furthermore, such a system would
+likely be implemented in an ad-hoc fashion, as different drivers will
+provide their information in different ways.
 Devfs is much cleaner, because it (natually) has a uniform mechanism
 to provide this information: the device nodes themselves!
 
@@ -349,8 +351,8 @@
 
 FreeBSD-current now has a devfs implementation. Solaris 2 has a
 pseudo-devfs (something akin to scsidev but for all devices, with some
-unspecified kernel support). BeOS  and Plan9 also have it. SGI's IRIX
-6.4 and above also have a device filesystem.
+unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's
+IRIX 6.4 and above also have a device filesystem.
 
 While we shouldn't just automatically do something because others do
 it, we should not ignore the work of others either. FreeBSD has a lot
@@ -875,10 +877,7 @@
 
 Please note that using dynamically allocated block device numbers may
 break the NFS daemons (both user and kernel mode), which expect dev_t
-for a given device to be constant over reboots. A simple reboot, with
-no change in your hardware layout, would result in the same device
-numbers being allocated, and hence will not cause a problem for NFS
-daemons.
+for a given device to be constant over the lifetime of remote mounts.
 
 A final note on this scheme: since it doesn't increase the size of
 device numbers, there are no compatibility issues with userspace.
diff -u --recursive --new-file v2.3.49/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt
--- v2.3.49/linux/Documentation/networking/cs89x0.txt	Wed Aug 18 11:37:57 1999
+++ linux/Documentation/networking/cs89x0.txt	Fri Mar  3 12:56:13 2000
@@ -1,635 +1,666 @@
-CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
-Linux Network Interface Driver ver. 1.02
-===============================================================================
- 
-
-TABLE OF CONTENTS
-
-1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
-    1.1 Product Overview 
-    1.2 Driver Description
-	1.2.1 Driver Name
-	1.2.2 File in the Driver Package
-    1.3 System Requirements
-    1.4 Licensing Information
-
-2.0 ADAPTER INSTALLATION and CONFIGURATION
-    2.1 CS8900-based Adapter Configuration
-    2.2 CS8920-based Adapter Configuration 
-
-3.0 LOADING THE DRIVER AS A MODULE
-
-4.0 COMPILING THE DRIVER
-    4.1 Compiling the Driver As a Loadable Module
-    4.2 Compiling the Driver Into the Kernel
-    4.3 Compiling the Driver for a Linux v1.2.13 Kernel
-
-5.0 TESTING AND TROUBLESHOOTING
-    5.1 Known Defects and Limitations
-    5.2 Testing the Adapter
-        5.2.1 Diagnostic Self-Test
-        5.2.2 Diagnostic Network Test
-    5.3 Using the Adapter's LEDs
-    5.4 Resolving I/O Conflicts
-
-6.0 TECHNICAL SUPPORT
-    6.1 Contacting Crystal's Technical Support
-    6.2 Information Required Before Contacting Technical Support
-    6.3 Obtaining the Latest Driver Version
-        6.3.1 Crystal's Web Site
-        6.3.2 Crystal's Bulletin Board Service
-
-
-
-1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS
-===============================================================================
-
-
-1.1 PRODUCT OVERVIEW
-
-The CS8900-based ISA Ethernet Adapters from Crystal Semiconductor follow 
-IEEE 802.3 standards and support half or full-duplex operation in ISA bus 
-computers on 10 Mbps Ethernet networks.  The adapters are designed for 
-operation in 16-bit ISA or EISA bus expansion slots and are available in 
-10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5
-or fiber networks).  
-
-CS8920-based adapters are similar to the CS8900-based adapter with additional 
-features for Plug and Play (PnP) support and Wakeup Frame recognition.  As 
-such, the configuration procedures differ somewhat between the two types of 
-adapters.  Refer to the "Adapter Configuration" section for details on 
-configuring both types of adapters.
-
-
-1.2 DRIVER DESCRIPTION
-
-The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux v1.2.13 
-and v2.0 (or greater) kernels.  It can be compiled directly into the kernel or 
-loaded at run-time as a device driver module.
-
-1.2.1 Driver Name: cs89x0
-
-1.2.2 Files in the Driver Archive:
-
-  readme.txt  - this file
-  release.txt - known defects and modification log
-  cs89x0.c    - driver C code
-  cs89x0.h    - driver header file
-  cs89x0.o    - pre-compiled module (for v2.0 kernel)
-
-
-
-1.3 SYSTEM REQUIREMENTS
-
-The following hardware is required:
-
-   * Crystal LAN (CS8900/20-based) Ethernet ISA Adapter   
-
-   * IBM or IBM-compatible PC with:
-     * An 80386 or higher processor
-     * 16 bytes of contiguous IO space available between 210h - 370h
-     * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920).
-
-   * Appropriate cable (and connector for AUI, 10BASE-2) for your network
-     topology.
-
-The following software is required:
-
-   * LINUX kernel version 1.2.13 or 2.X
-
-   * CS8900/20 Setup Utility (DOS-based)
-
-   * LINUX kernel sources for your kernel (if compiling into kernel)
-
-   * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel 
-     or a module)   
-
-
-
-1.4 LICENSING INFORMATION
-
-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, version 1.
-
-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.
-
-For a full copy of the GNU General Public License, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-
-2.0 ADAPTER INSTALLATION and CONFIGURATION
-===============================================================================
-
-Both the CS8900 and CS8920-based adapters can be configured using parameters 
-stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup 
-Utility if you want to change the adapter's configuration in EEPROM.  
-
-When loading the driver as a module, you can specify many of the adapter's 
-configuration parameters on the command-line to override the EEPROM's settings 
-or for interface configuration when an EEPROM is not used. (CS8920-based 
-adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE.
-
-Since the CS8900/20 Setup Utility is a DOS-based application, you must install 
-and configure the adapter in a DOS-based system using the CS8900/20 Setup 
-Utility before installation in the target LINUX system.  (Not required if 
-installing a CS8900-based adapter and the default configuration is acceptable.)
-     
-
-2.1 CS8900-BASED ADAPTER CONFIGURATION
-
-CS8900-based adapters shipped from Crystal Semiconductor have been configured 
-with the following "default" settings:
-
-  Operation Mode:      Memory Mode
-  IRQ:                 10
-  Base I/O Address:    300
-  Memory Base Address: D0000
-  Optimization:	       DOS Client
-  Transmission Mode:   Half-duplex
-  BootProm:            None
-  Media Type:	       Autodetect (3-media cards) or 
-                       10BASE-T (10BASE-T only adapter)
-
-You should only change the default configuration settings if conflicts with 
-another adapter exist. To change the adapter's configuration, run the 
-CS8900/20 Setup Utility. 
-
-
-2.2 CS8920-BASED ADAPTER CONFIGURATION
-
-CS8920-based adapters are shipped from Crystal Semiconductor configured as Plug
-and Play (PnP) enabled.  However, since Linux is not currently a PnP compatible 
-operating system, you must install the CS8920 adapter in a DOS-based PC and 
-run the CS8900/20 Setup Utility to disable PnP and configure the adapter before
-installation in the target Linux system.  Failure to do this will leave the 
-adapter inactive and the driver will be unable to communicate with the
-adapter.
-
-
-        **************************************************************** 
-        *                    CS8920-BASED ADAPTERS:                    *
-        *                                                              * 
-        * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT.  * 
-        * SCO UNIX IS NOT A PnP OPERATING SYSTEM. THEREFORE, YOU MUST  *
-        * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND   *
-        * TO ACTIVATE THE ADAPTER.                                     *
-        ****************************************************************
-
-
-
-
-3.0 LOADING THE DRIVER AS A MODULE
-===============================================================================
-
-If the driver is compiled as a loadable module, you can load the driver module
-with the 'insmod' command.  Many of the adapter's configuration parameters can 
-be specified as command-line arguments to the load command.  This facility 
-provides a means to override the EEPROM's settings or for interface 
-configuration when an EEPROM is not used.
-
-Example:
-
-    insmod cs89x0.o io=0x200 irq=0xA media=aui
-
-This example loads the module and configures the adapter to use an IO port base
-address of 200h, interrupt 10, and use the AUI media connection.  The following
-configuration options are available on the command line:
-
-* io=###              - specify IO address (200h-360h)
-* irq=##              - specify interrupt level
-* mmode=#####         - specify memory base address
-* dma=#               - specify DMA channel
-* media=rj45          - specify media type
-   or media=2
-   or media=aui
-   or medai=auto
-* duplex=f            - specify forced half/full/autonegotiate duplex
-   or duplex=h
-   or duplex=auto
-* debug=#             - debug level
-
-NOTES:
-* If an EEPROM is present, any specified command-line parameter will override
-the corresponding configuration value stored in EEPROM.
-
-* If no "io" or "mmode" parameter is specified on the command-line, the driver
-will scan for the adapter.  When scanning, the driver only reads I/O ports.  
-This sometimes is not sufficient, (e.g. after a warm boot).  If you wish to 
-allow the driver to perform a more aggressive scan (one write to the IO base 
-addresses to reset the data port pointer) you can specify an I/O address with 
-an address value one greater than the configured address.  Example, to scan for
-an adapter located at IO base 0x300, specify an IO address of 0x301.  Only 
-ports between 200h and 360h at 20h intervals are scanned.  
-
-* The "duplex=auto" parameter is only supported for the CS8920.
-
-* The minimum command-line configuration required if an EEPROM is not present
-is:
-
-  * io or mmode base address
-  * irq 
-  * media type (no autodetect)
-
-The following additional parameters are CS89XX defaults (values used with no 
-EEPROM or command-line argument).
-
-  * DMA Burst = enabled
-  * IOCHRDY Enabled = enabled
-  * UseSA = enabled
-  * CS8900 defaults to half-duplex if not specified on command-line
-  * CS8920 defaults to autoneg if not specified on command-line
-  * Use reset defaults for other config parameters
-
-* You can use ifconfig to set the adapter's Ethernet address.
-
-
-
-
-4.0 COMPILING THE DRIVER
-===============================================================================
-
-The cs89x0 driver can be compiled directly into the kernel or compiled into
-a loadable device driver module.
-
-NOTE: This part of the description relates to adding the driver to a kernel
-not containing the cs89x0 driver. This kernel already contains it.
-
-4.1 COMPILING THE DRIVER AS A LOADABLE MODULE
-
-To compile the driver into a loadable module, use the following command 
-(single command line, without quotes):
-
-"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall 
--Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS 
--c cs89x0.c"
-
-
-4.2 COMPILING THE DRIVER INTO THE KERNEL
-
-To compile the driver directly into the kernel requires editing four 
-configuration files, copying the source file to the /linux/drivers/net
-directory and then running the make utility to rebuild the kernel.
-
-1. Edit the following configuration files by adding the statements as
-indicated.  (When possible, try to locate the added text to the section of the
-file containing similar statements).
-
-a.) In /usr/src/linux/drivers/net/CONFIG, add
-
-CS89x0_OPTS   =
-
-Example:
-
- WD_OPTS	= #-DWD_SHMEM=0xDD000
- EL2_OPTS	= #-DEL2_AUI
- CS89x0_OPTS	=                
- NE_OPTS	=
- HP_OPTS	=
- PLIP_OPTS	=
-
-
-b.) In /usr/src/linux/drivers/net/Config.in, add:
-
-tristate 'CS89x0 support' CONFIG_CS89x0
-
-Example:
-
-     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
-     fi
-
-     tristate 'CS89x0 support' CONFIG_CS89x0
-
-     tristate 'NE2000/NE1000 support' CONFIG_NE2000
-     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-       tristate 'NI5210 support' CONFIG_NI52
-
-
-c.) In /usr/src/linux/drivers/net/Makefile, add the following lines: 
-
-ifeq ($(CONFIG_CS89x0),y)
-L_OBJS += cs89x0.o
-else
-  ifeq ($(CONFIG_CS89x0),m)
-  M_OBJS += cs89x0.o
-  endif
-endif
-
-
-d.) In /linux/drivers/net/Space.c file, add the line:
-
-extern int cs89x0_probe(struct net_device *dev);
-
-
-Example:
-
- extern int ultra_probe(struct net_device *dev);
- extern int wd_probe(struct net_device *dev);
- extern int el2_probe(struct net_device *dev);
-
- extern int cs89x0_probe(struct net_device *dev);
-
- extern int ne_probe(struct net_device *dev);
- extern int hp_probe(struct net_device *dev);
- extern int hp_plus_probe(struct net_device *dev);
-
-
-Also add:
-
- #ifdef CONFIG_CS89x0
- 	&& cs89x0_probe(dev)
- #endif
-
-
-2.) Copy the driver source files (cs89x0.c and cs89x0.h) and this README file 
-into the /usr/src/linux/drivers/net directory.
-
-
-3.) Run 'make config' followed by 'make dep' and finally 'make' to rebuild 
-the kernel. 
-
-
-4.3 COMPILING THE DRIVER FOR A LINUX v1.2.13 KERNEL
-
-To compile the driver for Linux v1.2.13 (into the kernel or as a module), 
-change the "SUPPORTS" define at the beginning of the cs89x0.c file.  
-Example:
-
-#define SUPPORTS_1_2_13 1   /* supports Linux kernel v1.2.13 */
-   or
-#define SUPPORTS_1_2_13 0   /* supports Linux kernel v2.0 (default) */
-
-
-
-5.0 TESTING AND TROUBLESHOOTING
-===============================================================================
-
-5.1 KNOWN DEFECTS and LIMITATIONS
-
-Refer to the RELEASE.TXT file distributed as part of this archive for a list of 
-known defects, driver limitations, and work arounds.
-
-
-5.2 TESTING THE ADAPTER
-
-Once the adapter has been installed and configured, the diagnostic option of 
-the CS8900/20 Setup Utility can be used to test the functionality of the 
-adapter and its network connection.  Use the diagnostics 'Self Test' option to
-test the functionality of the adapter with the hardware configuration you have
-assigned. You can use the diagnostics 'Network Test' to test the ability of the
-adapter to communicate across the Ethernet with another PC equipped with a 
-CS8900/20-based adapter card (it must also be running the CS8900/20 Setup 
-Utility).
-
-         NOTE: The Setup Utility's diagnostics are designed to run in a
-         DOS-only operating system environment.  DO NOT run the diagnostics 
-         from a DOS or command prompt session under Windows 95, Windows NT, 
-         OS/2, or other operating system.
-
-	[AC - Question : Do they work in DOSEMU ?]
-
-To run the diagnostics tests on the CS8900/20 adapter:
-
-   1.) Boot DOS on the PC and start the CS8900/20 Setup Utility.
-
-   2.) The adapter's current configuration is displayed.  Hit the ENTER key to
-       get to the main menu.
-
-   4.) Select 'Diagnostics' (ALT-G) from the main menu.  
-       * Select 'Self-Test' to test the adapter's basic functionality.
-       * Select 'Network Test' to test the network connection and cabling.
-
-
-5.2.1 DIAGNOSTIC SELF-TEST
-
-The diagnostic self-test checks the adapter's basic functionality as well as 
-its ability to communicate across the ISA bus based on the system resources 
-assigned during hardware configuration.  The following tests are performed:
-
-   * IO Register Read/Write Test
-     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 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 ensures there are no conflicts with the assigned IRQ
-     signal.
-
-   * EEPROM Test
-     The EEPROM test ensures the EEPROM can be read.
-
-   * Chip RAM Test
-     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 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 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
-     Boot PROM option.)
-
-Failure of a test item indicates a possible system resource conflict with 
-another device on the ISA bus.  In this case, you should use the Manual Setup 
-option to reconfigure the adapter by selecting a different value for the system
-resource that failed.
-
-
-5.2.2 DIAGNOSTIC NETWORK TEST
-
-The Diagnostic Network Test verifies a working network connection by 
-transferring data between two CS8900/20 adapters installed in different PCs 
-on the same network. (Note: the diagnostic network test should not be run 
-between two nodes across a router.) 
-
-This test requires that each of the two PCs have a CS8900/20-based adapter
-installed and have the CS8900/20 Setup Utility running.  The first PC is 
-configured as a Responder and the other PC is configured as an Initiator.  
-Once the Initiator is started, it sends data frames to the Responder which 
-returns the frames to the Initiator.
-
-The total number of frames received and transmitted are displayed on the 
-Initiator's display, along with a count of the number of frames received and 
-transmitted OK or in error.  The test can be terminated anytime by the user at 
-either PC.
-
-To setup the Diagnostic Network Test:
-
-    1.) Select a PC with a CS8900/20-based adapter and a known working network
-        connection to act as the Responder.  Run the CS8900/20 Setup Utility 
-        and select 'Diagnostics -> Network Test -> Responder' from the main 
-        menu.  Hit ENTER to start the Responder.
-
-    2.) Return to the PC with the CS8900/20-based adapter you want to test and
-        start the CS8900/20 Setup Utility. 
-
-    3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'.
-        Hit ENTER to start the test.
- 
-You may stop the test on the Initiator at any time while allowing the Responder
-to continue running.  In this manner, you can move to additional PCs and test 
-them by starting the Initiator on another PC without having to stop/start the 
-Responder.
- 
-
-
-5.3 USING THE ADAPTER'S LEDs
-
-The 2 and 3-media adapters have two LEDs visible on the back end of the board 
-located near the 10Base-T connector.  
-
-Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T 
-connection.  (Only applies to 10Base-T.  The green LED has no significance for
-a 10Base-2 or AUI connection.)
-
-TX/RX LED: The yellow LED lights briefly each time the adapter transmits or 
-receives data. (The yellow LED will appear to "flicker" on a typical network.)
-
-
-5.4 RESOLVING I/O CONFLICTS
-
-An IO conflict occurs when two or more adapter use the same ISA resource (IO 
-address, memory address or IRQ).  You can usually detect an IO conflict in one 
-of four ways after installing and or configuring the CS8900/20-based adapter:
-
-    1.) The system does not boot properly (or at all).
-
-    2.) The driver can not communicate with the adapter, reporting an "Adapter
-        not found" error message.
-
-    3.) You cannot connect to the network or the driver will not load.
-
-    4.) If you have configured the adapter to run in memory mode but the driver
-        reports it is using IO mode when loading, this is an indication of a
-        memory address conflict.
-
-If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a 
-diagnostic self-test.  Normally, the ISA resource in conflict will fail the 
-self-test.  If so, reconfigure the adapter selecting another choice for the 
-resource in conflict.  Run the diagnostics again to check for further IO 
-conflicts.
-
-In some cases, such as when the PC will not boot, it may be necessary to remove
-the adapter and reconfigure it by installing it in another PC to run the 
-CS8900/20 Setup Utility.  Once reinstalled in the target system, run the 
-diagnostics self-test to ensure the new configuration is free of conflicts 
-before loading the driver again.
-
-When manually configuring the adapter, keep in mind the typical ISA system 
-resource usage as indicated in the tables below.
-
-I/O Address    	Device                        IRQ      Device
------------    	--------                      ---      --------
- 200-20F       	Game I/O adapter               3       COM2, Bus Mouse
- 230-23F       	Bus Mouse                      4       COM1
- 270-27F       	LPT3: third parallel port      5       LPT2
- 2F0-2FF       	COM2: second serial port       6       Floppy Disk controller
- 320-32F       	Fixed disk controller          7       LPT1
-                                      	       8       Real-time Clock
-                                               9       EGA/VGA display adapter    
-                                              12       Mouse (PS/2)                              
-Memory Address  Device                        13       Math Coprocessor
---------------  ---------------------         14       Hard Disk controller
-A000-BFFF	EGA Graphics Adapter
-A000-C7FF	VGA Graphics Adapter
-B000-BFFF	Mono Graphics Adapter
-B800-BFFF	Color Graphics Adapter
-E000-FFFF	AT BIOS
-
-
-
-
-6.0 TECHNICAL SUPPORT
-===============================================================================
-
-6.1 CONTACTING CRYSTAL'S TECHNICAL SUPPORT
-
-Crystal's CS89XX Technical Application Support can be reached at:
-
-Telephone  :(800) 888-5016 (from inside U.S. and Canada)
-           :(512) 442-7555 (from outside the U.S. and Canada)
-Fax	   :(512) 912-3871
-E-mail	   :ethernet@crystal.cirrus.com
-WWW        :http://www.crystal.com
-
-
-6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT
-
-Before contacting Crystal for technical support, be prepared to provide as much
-of the following information as possible. 
-
-1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.)
-
-2.) Adapter configuration
-
-    * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel
-    * Plug and Play enabled/disabled (CS8920-based adapters only)
-    * Configured for media auto-detect or specific media type (which type).    
-
-3.) PC System's Configuration
-
-    * Plug and Play system (yes/no)
-    * BIOS (make and version)
-    * System make and model
-    * CPU (type and speed)
-    * System RAM
-    * SCSI Adapter
-
-4.) Software
-
-    * CS89XX driver and version
-    * Your network operating system and version
-    * Your system's OS version 
-    * Version of all protocol support files
-
-5.) Any Error Message displayed.
-
-
-
-6.3 OBTAINING THE LATEST DRIVER VERSION
-
-You can obtain the latest CS89XX drivers and support software from Crystal's 
-BBS or Web site.  You can also contact Crystal's Technical Support (email:
-ethernet@crystal.cirrus.com) and request that you be registered for automatic 
-software-update notification.
-
-
-6.3.1 CRYSTAL'S WEB SITE
-
-Crystal Semiconductor maintains a web page at http://www.crystal.com with the
-latest drivers and technical publications.
-
-
-6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
-
-Access to the BBS is available 24 hours a day, seven days a week. Baud 
-rates from 300K to 14.4K are supported as well as most common file transfer 
-protocols.  
-
-To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, 
-and no parity.  Dial (512) 441-3265 and press <ENTER> after connection is made.
-Login using your account name and password.  (If you do not have an account, 
-you may login as "GUEST".  No password is required for the Guest account.)
-
-From the main system menu, select the "Enter Public File Area" menu option.  
-From the Public File Area menu, select the "LAN (Local Area Network)" file
-area.  A list of the latest drivers and support utilities available for the
-CS89XX ISA Ethernet adapter will be presented along with the option to download
-the file(s) of your choice.
-
-
+
+NOTE
+----
+
+This document was contributed by Cirrus Logic for kernel 2.2.5.  This version
+has been updated for 2.3.48 by Andrew Morton <andrewm@uow.edu.au>
+
+Cirrus make a copy of this driver available at their website, as
+described below.  In general, you should use the driver version which
+comes with your Linux distribution.
+
+
+
+CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS
+Linux Network Interface Driver ver. 2.00 <kernel 2.3.48>
+===============================================================================
+ 
+
+TABLE OF CONTENTS
+
+1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS
+    1.1 Product Overview 
+    1.2 Driver Description
+	1.2.1 Driver Name
+	1.2.2 File in the Driver Package
+    1.3 System Requirements
+    1.4 Licensing Information
+
+2.0 ADAPTER INSTALLATION and CONFIGURATION
+    2.1 CS8900-based Adapter Configuration
+    2.2 CS8920-based Adapter Configuration 
+
+3.0 LOADING THE DRIVER AS A MODULE
+
+4.0 COMPILING THE DRIVER
+    4.1 Compiling the Driver as a Loadable Module
+    4.2 Compiling the driver to support memory mode
+    4.3 Compiling the driver to support Rx DMA 
+    4.4 Compiling the Driver into the Kernel
+
+5.0 TESTING AND TROUBLESHOOTING
+    5.1 Known Defects and Limitations
+    5.2 Testing the Adapter
+        5.2.1 Diagnostic Self-Test
+        5.2.2 Diagnostic Network Test
+    5.3 Using the Adapter's LEDs
+    5.4 Resolving I/O Conflicts
+
+6.0 TECHNICAL SUPPORT
+    6.1 Contacting Cirrus Logic's Technical Support
+    6.2 Information Required Before Contacting Technical Support
+    6.3 Obtaining the Latest Driver Version
+    6.4 Current maintainer
+
+
+
+1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS
+===============================================================================
+
+
+1.1 PRODUCT OVERVIEW
+
+The CS8900-based ISA Ethernet Adapters from Cirrus Logic follow 
+IEEE 802.3 standards and support half or full-duplex operation in ISA bus 
+computers on 10 Mbps Ethernet networks.  The adapters are designed for operation 
+in 16-bit ISA or EISA bus expansion slots and are available in 
+10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 
+or fiber networks).  
+
+CS8920-based adapters are similar to the CS8900-based adapter with additional 
+features for Plug and Play (PnP) support and Wakeup Frame recognition.  As 
+such, the configuration procedures differ somewhat between the two types of 
+adapters.  Refer to the "Adapter Configuration" section for details on 
+configuring both types of adapters.
+
+
+1.2 DRIVER DESCRIPTION
+
+The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux
+v2.3.48 or greater kernel.  It can be compiled directly into the kernel
+or loaded at run-time as a device driver module.
+
+1.2.1 Driver Name: cs89x0
+
+1.2.2 Files in the Driver Archive:
+
+The files in the driver at Cirrus' website include:
+
+  readme.txt         - this file
+  build              - batch file to compile cs89x0.c.
+  cs89x0.c           - driver C code
+  cs89x0.h           - driver header file
+  cs89x0.o           - pre-compiled module (for v2.2.5 kernel)
+  config/Config.in   - sample file to include cs89x0 driver in the kernel.
+  config/Makefile    - sample file to include cs89x0 driver in the kernel.
+  config/Space.c     - sample file to include cs89x0 driver in the kernel.
+
+
+
+1.3 SYSTEM REQUIREMENTS
+
+The following hardware is required:
+
+   * Cirrus Logic LAN (CS8900/20-based) Ethernet ISA Adapter   
+
+   * IBM or IBM-compatible PC with:
+     * An 80386 or higher processor
+     * 16 bytes of contiguous IO space available between 210h - 370h
+     * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920).
+
+   * Appropriate cable (and connector for AUI, 10BASE-2) for your network
+     topology.
+
+The following software is required:
+
+* LINUX kernel version 2.3.48 or higher
+
+   * CS8900/20 Setup Utility (DOS-based)
+
+   * LINUX kernel sources for your kernel (if compiling into kernel)
+
+   * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel 
+     or a module)   
+
+
+
+1.4 LICENSING INFORMATION
+
+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, version 1.
+
+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.
+
+For a full copy of the GNU General Public License, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+
+2.0 ADAPTER INSTALLATION and CONFIGURATION
+===============================================================================
+
+Both the CS8900 and CS8920-based adapters can be configured using parameters 
+stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup 
+Utility if you want to change the adapter's configuration in EEPROM.  
+
+When loading the driver as a module, you can specify many of the adapter's 
+configuration parameters on the command-line to override the EEPROM's settings 
+or for interface configuration when an EEPROM is not used. (CS8920-based 
+adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE.
+
+Since the CS8900/20 Setup Utility is a DOS-based application, you must install 
+and configure the adapter in a DOS-based system using the CS8900/20 Setup 
+Utility before installation in the target LINUX system.  (Not required if 
+installing a CS8900-based adapter and the default configuration is acceptable.)
+     
+
+2.1 CS8900-BASED ADAPTER CONFIGURATION
+
+CS8900-based adapters shipped from Cirrus Logic have been configured 
+with the following "default" settings:
+
+  Operation Mode:      Memory Mode
+  IRQ:                 10
+  Base I/O Address:    300
+  Memory Base Address: D0000
+  Optimization:	       DOS Client
+  Transmission Mode:   Half-duplex
+  BootProm:            None
+  Media Type:	       Autodetect (3-media cards) or 
+                       10BASE-T (10BASE-T only adapter)
+
+You should only change the default configuration settings if conflicts with 
+another adapter exists. To change the adapter's configuration, run the 
+CS8900/20 Setup Utility. 
+
+
+2.2 CS8920-BASED ADAPTER CONFIGURATION
+
+CS8920-based adapters are shipped from Cirrus Logic configured as Plug
+and Play (PnP) enabled.  However, since the cs89x0 driver does NOT
+support PnP, you must install the CS8920 adapter in a DOS-based PC and
+run the CS8900/20 Setup Utility to disable PnP and configure the
+adapter before installation in the target Linux system.  Failure to do
+this will leave the adapter inactive and the driver will be unable to
+communicate with the adapter.  
+
+
+        **************************************************************** 
+        *                    CS8920-BASED ADAPTERS:                    *
+        *                                                              * 
+        * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT.  * 
+        * THE CS89X0 DRIVER DOES NOT SUPPORT PnP. THEREFORE, YOU MUST  *
+        * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND   *
+        * TO ACTIVATE THE ADAPTER.                                     *
+        ****************************************************************
+
+
+
+
+3.0 LOADING THE DRIVER AS A MODULE
+===============================================================================
+
+If the driver is compiled as a loadable module, you can load the driver module
+with the 'modprobe' command.  Many of the adapter's configuration parameters can 
+be specified as command-line arguments to the load command.  This facility 
+provides a means to override the EEPROM's settings or for interface 
+configuration when an EEPROM is not used.
+
+Example:
+
+    insmod cs89x0.o io=0x200 irq=0xA media=aui
+
+This exmaple loads the module and configures the adapter to use an IO port base
+address of 200h, interrupt 10, and use the AUI media connection.  The following
+configuration options are available on the command line:
+
+* io=###               - specify IO address (200h-360h)
+* irq=##               - specify interrupt level
+* use_dma=1            - Enable DMA
+* dma=#                - specify dma channel (Driver is compiled to support
+                         Rx DMA only)
+* dmasize=# (16 or 64) - DMA size 16K or 64K.  Default value is set to 16.
+* media=rj45           - specify media type
+   or media=bnc
+   or media=aui
+   or medai=auto
+* duplex=full          - specify forced half/full/autonegotiate duplex
+   or duplex=half
+   or duplex=auto
+* debug=#              - debug level (only available if the driver was compiled
+                         for debugging)
+
+NOTES:
+
+a) If an EEPROM is present, any specified command-line parameter
+   will override the corresponding configuration value stored in
+   EEPROM.
+
+b) The "io" parameter must be specified on the command-line.  
+
+c) In case you can not re-load the driver because Linux system
+   returns the "device or resource busy" message, try to re-load it by
+   increment the IO port address by one.  The driver will write
+   commands to the IO base addresses to reset the data port pointer. 
+   You can specify an I/O address with an address value one greater
+   than the configured address.  Example, to scan for an adapter
+   located at IO base 0x300, specify an IO address of 0x301.  
+
+d) The "duplex=auto" parameter is only supported for the CS8920.
+
+e) The minimum command-line configuration required if an EEPROM is
+   not present is:
+
+   io 
+   irq 
+   media type (no autodetect)
+
+f) The following addtional parameters are CS89XX defaults (values
+   used with no EEPROM or command-line argument).
+
+   * DMA Burst = enabled
+   * IOCHRDY Enabled = enabled
+   * UseSA = enabled
+   * CS8900 defaults to half-duplex if not specified on command-line
+   * CS8920 defaults to autoneg if not specified on command-line
+   * Use reset defaults for other config parameters
+   * dma_mode = 0
+
+g) You can use ifconfig to set the adapter's Ethernet address.
+
+h) Many Linux distributions use the 'modprobe' command to load
+   modules.  This program uses the '/etc/conf.modules' file to
+   determine configuration information which is passed to a driver
+   module when it is loaded.  All the configuration options which are
+   described above may be placed within /etc/conf.modules.
+
+   For example:
+
+   > cat /etc/conf.modules
+   ...
+   alias eth0 cs89x0
+   options cs89x0 io=0x0200 dma=5 use_dma=1
+   ...
+
+   In this example we are telling the module system that the
+   ethernet driver for this machine should use the cs89x0 driver.  We
+   are asking 'modprobe' to pass the 'io', 'dma' and 'use_dma'
+   arguments to the driver when it is loaded.
+
+i) Cirrus recommend that the cs89x0 use the ISA DMA channels 5, 6 or
+   7.  You will probably find that other DMA channels will not work.
+
+j) The cs89x0 supports DMA for receiving only.  DMA mode is
+   significantly more efficient.  Flooding a 400 MHz Celeron machine
+   with large ping packets consumes 82% of its CPU capacity in non-DMA
+   mode.  With DMA this is reduced to 45%.
+
+k) If your Linux kernel was compiled with inbuilt plug-and-play
+   support you will be able to find information about the cs89x0 card
+   with the command
+
+   cat /proc/isapnp
+
+l) If during DMA operation you find erratic behavior or network data
+   corruption you should use your PC's BIOS to slow the EISA bus clock.
+
+
+4.0 COMPILING THE DRIVER
+===============================================================================
+
+The cs89x0 driver can be compiled directly into the kernel or compiled into
+a loadable device driver module.
+
+
+4.1 COMPILING THE DRIVER AS A LOADABLE MODULE
+
+To compile the driver into a loadable module, use the following command 
+(single command line, without quotes):
+
+"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall 
+-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS 
+-c cs89x0.c"
+
+4.2 COMPILING THE DRIVER TO SUPPORT MEMORY MODE
+
+Support for memory mode was not carried over into the 2.3 series kernels.
+
+4.3 COMPILING THE DRIVER TO SUPPORT Rx DMA
+
+The compile-time optionality for DMA was removed in the 2.3 kernel
+series.  DMA support is now unconditionally part of the driver.  It is
+enabled by the 'use_dma=1' module option.
+
+4.4 COMPILING THE DRIVER INTO THE KERNEL
+
+If your Linux distribution already has support for the cs89x0 driver
+then simply copy the source file to the /usr/src/linux/drivers/net
+directory to replace the original ones and run the make utility to
+rebuild the kernel.  See Step 3 for rebuilding the kernel.
+
+If your Linux does not include the cs89x0 driver, you need to edit three 
+configuration files, copy the source file to the /usr/src/linux/drivers/net
+directory, and then run the make utility to rebuild the kernel.
+
+1. Edit the following configuration files by adding the statements as
+indicated.  (When possible, try to locate the added text to the section of the
+file containing similar statements).
+
+
+a.) In /usr/src/linux/drivers/net/Config.in, add:
+
+tristate 'CS89x0 support' CONFIG_CS89x0
+
+Example:
+
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
+     fi
+
+     tristate 'CS89x0 support' CONFIG_CS89x0
+
+     tristate 'NE2000/NE1000 support' CONFIG_NE2000
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       tristate 'NI5210 support' CONFIG_NI52
+
+
+b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: 
+
+ifeq ($(CONFIG_CS89x0),y)
+L_OBJS += cs89x0.o
+else
+  ifeq ($(CONFIG_CS89x0),m)
+  M_OBJS += cs89x0.o
+  endif
+endif
+
+
+c.) In /linux/drivers/net/Space.c file, add the line:
+
+extern int cs89x0_probe(struct device *dev);
+
+
+Example:
+
+ extern int ultra_probe(struct device *dev);
+ extern int wd_probe(struct device *dev);
+ extern int el2_probe(struct device *dev);
+
+ extern int cs89x0_probe(struct device *dev);
+
+ extern int ne_probe(struct device *dev);
+ extern int hp_probe(struct device *dev);
+ extern int hp_plus_probe(struct device *dev);
+
+
+Also add:
+
+ #ifdef CONFIG_CS89x0
+ 	{ cs89x0_probe,0 },
+ #endif
+
+
+2.) Copy the driver source files (cs89x0.c and cs89x0.h) 
+into the /usr/src/linux/drivers/net directory.
+
+
+3.) Go to /usr/src/linux directory and run 'make config' followed by 'make dep' 
+and finally 'make' (or make bzImage) to rebuild the kernel. 
+
+4.) Use the DOS 'setup' utility to disable plug and play on the NIC.
+
+
+5.0 TESTING AND TROUBLESHOOTING
+===============================================================================
+
+5.1 KNOWN DEFECTS and LIMITATIONS
+
+Refer to the RELEASE.TXT file distributed as part of this archive for a list of 
+known defects, driver limitations, and work arounds.
+
+
+5.2 TESTING THE ADAPTER
+
+Once the adapter has been installed and configured, the diagnostic option of 
+the CS8900/20 Setup Utility can be used to test the functionality of the 
+adapter and its network connection.  Use the diagnostics 'Self Test' option to
+test the functionality of the adapter with the hardware configuration you have
+assigned. You can use the diagnostics 'Network Test' to test the ability of the
+adapter to communicate across the Ethernet with another PC equipped with a 
+CS8900/20-based adapter card (it must also be running the CS8900/20 Setup 
+Utility).
+
+         NOTE: The Setup Utility's diagnostics are designed to run in a
+         DOS-only operating system environment.  DO NOT run the diagnostics 
+         from a DOS or command prompt session under Windows 95, Windows NT, 
+         OS/2, or other operating system.
+
+To run the diagnostics tests on the CS8900/20 adapter:
+
+   1.) Boot DOS on the PC and start the CS8900/20 Setup Utility.
+
+   2.) The adapter's current configuration is displayed.  Hit the ENTER key to
+       get to the main menu.
+
+   4.) Select 'Diagnostics' (ALT-G) from the main menu.  
+       * Select 'Self-Test' to test the adapter's basic functionality.
+       * Select 'Network Test' to test the network connection and cabling.
+
+
+5.2.1 DIAGNOSTIC SELF-TEST
+
+The diagnostic self-test checks the adapter's basic functionality as well as 
+its ability to communicate across the ISA bus based on the system resources 
+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 
+     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 
+     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
+     signal.
+
+   * EEPROM Test
+     The EEPROM test insures the EEPROM can be read.
+
+   * Chip RAM Test
+     The Chip RAM test insures the 4K 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 
+     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.
+     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
+     Boot PROM option.)
+
+Failure of a test item indicates a possible system resource conflict with 
+another device on the ISA bus.  In this case, you should use the Manual Setup 
+option to reconfigure the adapter by selecting a different value for the system
+resource that failed.
+
+
+5.2.2 DIAGNOSTIC NETWORK TEST
+
+The Diagnostic Network Test verifies a working network connection by 
+transferring data between two CS8900/20 adapters installed in different PCs 
+on the same network. (Note: the diagnostic network test should not be run 
+between two nodes across a router.) 
+
+This test requires that each of the two PCs have a CS8900/20-based adapter
+installed and have the CS8900/20 Setup Utility running.  The first PC is 
+configured as a Responder and the other PC is configured as an Initiator.  
+Once the Initiator is started, it sends data frames to the Responder which 
+returns the frames to the Initiator.
+
+The total number of frames received and transmitted are displayed on the 
+Initiator's display, along with a count of the number of frames received and 
+transmitted OK or in error.  The test can be terminated anytime by the user at 
+either PC.
+
+To setup the Diagnostic Network Test:
+
+    1.) Select a PC with a CS8900/20-based adapter and a known working network
+        connection to act as the Responder.  Run the CS8900/20 Setup Utility 
+        and select 'Diagnostics -> Network Test -> Responder' from the main 
+        menu.  Hit ENTER to start the Responder.
+
+    2.) Return to the PC with the CS8900/20-based adapter you want to test and
+        start the CS8900/20 Setup Utility. 
+
+    3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'.
+        Hit ENTER to start the test.
+ 
+You may stop the test on the Initiator at any time while allowing the Responder
+to continue running.  In this manner, you can move to additional PCs and test 
+them by starting the Initiator on another PC without having to stop/start the 
+Responder.
+ 
+
+
+5.3 USING THE ADAPTER'S LEDs
+
+The 2 and 3-media adapters have two LEDs visible on the back end of the board 
+located near the 10Base-T connector.  
+
+Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T 
+connection.  (Only applies to 10Base-T.  The green LED has no significance for
+a 10Base-2 or AUI connection.)
+
+TX/RX LED: The yellow LED lights briefly each time the adapter transmits or 
+receives data. (The yellow LED will appear to "flicker" on a typical network.)
+
+
+5.4 RESOLVING I/O CONFLICTS
+
+An IO conflict occurs when two or more adapter use the same ISA resource (IO 
+address, memory address or IRQ).  You can usually detect an IO conflict in one 
+of four ways after installing and or configuring the CS8900/20-based adapter:
+
+    1.) The system does not boot properly (or at all).
+
+    2.) The driver can not communicate with the adapter, reporting an "Adapter
+        not found" error message.
+
+    3.) You cannot connect to the network or the driver will not load.
+
+    4.) If you have configured the adapter to run in memory mode but the driver
+        reports it is using IO mode when loading, this is an indication of a
+        memory address conflict.
+
+If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a 
+diagnostic self-test.  Normally, the ISA resource in conflict will fail the 
+self-test.  If so, reconfigure the adapter selecting another choice for the 
+resource in conflict.  Run the diagnostics again to check for further IO 
+conflicts.
+
+In some cases, such as when the PC will not boot, it may be necessary to remove
+the adapter and reconfigure it by installing it in another PC to run the 
+CS8900/20 Setup Utility.  Once reinstalled in the target system, run the 
+diagnostics self-test to ensure the new configuration is free of conflicts 
+before loading the driver again.
+
+When manually configuring the adapter, keep in mind the typical ISA system 
+resource usage as indicated in the tables below.
+
+I/O Address    	Device                        IRQ      Device
+-----------    	--------                      ---      --------
+ 200-20F       	Game I/O adapter               3       COM2, Bus Mouse
+ 230-23F       	Bus Mouse                      4       COM1
+ 270-27F       	LPT3: third parallel port      5       LPT2
+ 2F0-2FF       	COM2: second serial port       6       Floppy Disk controller
+ 320-32F       	Fixed disk controller          7       LPT1
+                                      	       8       Real-time Clock
+                                                 9       EGA/VGA display adapter    
+                                                12       Mouse (PS/2)                              
+Memory Address  Device                          13       Math Coprocessor
+--------------  ---------------------           14       Hard Disk controller
+A000-BFFF	EGA Graphics Adpater
+A000-C7FF	VGA Graphics Adpater
+B000-BFFF	Mono Graphics Adapter
+B800-BFFF	Color Graphics Adapter
+E000-FFFF	AT BIOS
+
+
+
+
+6.0 TECHNICAL SUPPORT
+===============================================================================
+
+6.1 CONTACTING CIRRUS LOGIC'S TECHNICAL SUPPORT
+
+Cirrus Logic's CS89XX Technical Application Support can be reached at:
+
+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
+WWW        :http://www.cirrus.com
+
+
+6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT
+
+Before contacting Cirrus Logic for technical support, be prepared to provide as 
+Much of the following information as possible. 
+
+1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.)
+
+2.) Adapter configuration
+
+    * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel
+    * Plug and Play enabled/disabled (CS8920-based adapters only)
+    * Configured for media auto-detect or specific media type (which type).    
+
+3.) PC System's Configuration
+
+    * Plug and Play system (yes/no)
+    * BIOS (make and version)
+    * System make and model
+    * CPU (type and speed)
+    * System RAM
+    * SCSI Adapter
+
+4.) Software
+
+    * CS89XX driver and version
+    * Your network operating system and version
+    * Your system's OS version 
+    * Version of all protocol support files
+
+5.) Any Error Message displayed.
+
+
+
+6.3 OBTAINING THE LATEST DRIVER VERSION
+
+You can obtain the latest CS89XX drivers and support software from Cirrus Logic's 
+Web site.  You can also contact Cirrus Logic's Technical Support (email:
+ethernet@crystal.cirrus.com) and request that you be registered for automatic 
+software-update notification.
+
+Cirrus Logic maintains a web page at http://www.cirrus.com with the
+the latest drivers and technical publications.
+
+
+6.4 Current maintainer
+
+In February 2000 the maintenance of this driver was assumed by Andrew
+Morton <andrewm@uow.edu.au>
+
+
diff -u --recursive --new-file v2.3.49/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- v2.3.49/linux/Documentation/usb/usb-serial.txt	Wed Feb 16 17:03:51 2000
+++ linux/Documentation/usb/usb-serial.txt	Tue Mar  7 11:24:19 2000
@@ -67,6 +67,32 @@
   http://usbvisor.sourceforge.net/
 
 
+Keyspan PDA Serial Adapter
+
+  Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
+  sold in Macintosh catalogs, comes in a translucent white/green dongle).
+  Fairly simple device. Firmware is homebrew.
+
+Current status:
+ Things that work:
+   basic input/output (tested with 'cu')
+   blocking write when serial line can't keep up
+   changing baud rates (up to 115200)
+   getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC})
+   sending break (although duration looks suspect)
+ Things that don't:
+   device strings (as logged by kernel) have trailing binary garbage
+   device ID isn't right, might collide with other Keyspan products
+   changing baud rates ought to flush tx/rx to avoid mangled half characters
+ Big Things on the todo list:
+   parity, 7 vs 8 bits per char, 1 or 2 stop bits
+   HW flow control
+   not all of the standard USB descriptors are handled: Get_Status, Set_Feature
+   O_NONBLOCK, select()
+
+ The device usually appears at /dev/ttyUSB1 .
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
diff -u --recursive --new-file v2.3.49/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- v2.3.49/linux/Documentation/video4linux/bttv/CARDLIST	Tue Jan 11 22:31:36 2000
+++ linux/Documentation/video4linux/bttv/CARDLIST	Mon Mar  6 15:32:30 2000
@@ -1,5 +1,5 @@
 bttv.o
-  card=0 - unknown
+  card=0 -  *** UNKNOWN *** 
   card=1 - MIRO PCTV
   card=2 - Hauppauge old
   card=3 - STB
@@ -33,6 +33,10 @@
   card=31 - iProTV
   card=32 - Intel Create and Share PCI
   card=33 - Terratec TerraTValue
+  card=34 - Leadtek WinFast 2000
+  card=35 - Chronos Video Shuttle II
+  card=36 - Typhoon TView TV/FM Tuner
+  card=37 - PixelView PlayTV pro
 
 tuner.o
   type=0 - Temic PAL
diff -u --recursive --new-file v2.3.49/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options
--- v2.3.49/linux/Documentation/video4linux/bttv/Insmod-options	Fri Jan  7 19:13:21 2000
+++ linux/Documentation/video4linux/bttv/Insmod-options	Mon Mar  6 15:32:30 2000
@@ -14,11 +14,19 @@
                                 but this might also help with other chipsets
 		bigendian=n	Set the endianness of the gfx framebuffer.
 				Default is native endian.
-		fieldnr=1	Count fields.  Some TV descrambling software
+		fieldnr=0/1	Count fields.  Some TV descrambling software
 				needs this, for others it only generates
-				50 useless IRQs/sec.
+				50 useless IRQs/sec.  default is 0 (off).
 		autoload=0/1	autoload helper modules (tuner, audio).
 				default is 1 (on).
+		verbose=0/1/2	verbose level (at insmod time, while looking at
+				the hardware).  default is 1.
+		debug=0/1	debug messages (for capture).
+				default is 0 (off).
+		gbuffers=2-64	number of capture buffers for mmap'ed capture.
+				default is 2.
+                gbufsize=n      size of capture buffers. default and
+                                maximum value is 0x208000 (~2MB)
 
 	remap, card, radio and pll accept up to four comma-separated arguments
 	(for multiple boards).
@@ -59,12 +67,12 @@
 	insmod args:
 		debug=1		print some debug info to the syslog.
 
-tda9855.o
-	The driver for the tda9855 audio chip.  Afaik, only the 
-        Diamond DTV2000 has this chip.
+tda985x.o
+	The driver for the tda9850/55 audio chips.
 
 	insmod args:
 		debug=1		print some debug info to the syslog.
+		chip=9850/9855	set the chip type.
 
 tuner.o
 	The tuner driver.  You need this unless you want to use only
diff -u --recursive --new-file v2.3.49/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README
--- v2.3.49/linux/Documentation/video4linux/bttv/README	Tue Jan 11 22:31:36 2000
+++ linux/Documentation/video4linux/bttv/README	Mon Mar  6 15:32:30 2000
@@ -12,6 +12,13 @@
 kernel, download it from:
 	http://www2.lm-sensors.nu/~lm78/download.html
 
+You'll need at least these i2c config options for bttv:
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+
+The latest bttv version is available here:
+	http://www.in-berlin.de/User/kraxel/v4l/
+
 You'll find Ralphs original (mostly outdated) documentation in the
 ralphs-doc subdirectory.
 
diff -u --recursive --new-file v2.3.49/linux/Documentation/zorro.txt linux/Documentation/zorro.txt
--- v2.3.49/linux/Documentation/zorro.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/zorro.txt	Tue Mar  7 10:52:41 2000
@@ -0,0 +1,116 @@
+		Writing Device Drivers for Zorro Devices
+		----------------------------------------
+
+Written by Geert Uytterhoeven <geert@linux-m68k.org>
+Last revised: February 27, 2000
+
+
+1. Introduction
+---------------
+
+The Zorro bus is the bus used in the Amiga family of computers. Thanks to
+AutoConfig(tm), it's is 100% Plug-and-Play.
+
+There are two types of Zorro busses, Zorro II and Zorro III:
+
+  - The Zorro II address space is 24-bit and lies within the first 16 MB of the
+    Amiga's address map.
+
+  - Zorro III is a 32-bit extension of Zorro II, which is backwards compatible
+    with Zorro II. The Zorro III address space lies outside the first 16 MB.
+
+
+2. Probing for Zorro Devices
+----------------------------
+
+Zorro devices are found by calling `zorro_find_device()', which returns a
+pointer to the `next' Zorro device with the specified Zorro ID. A probe loop
+for the board with Zorro ID `ZORRO_PROD_xxx' looks like:
+
+    struct zorro_dev *z = NULL;
+
+    while ((z = zorro_find_device(ZORRO_PROD_xxx, z))) {
+	if (!zorro_request_region(z->resource.start+MY_START, MY_SIZE,
+				  "My explanation"))
+	strcpy(z->name, "My board name");
+	...
+    }
+
+`ZORRO_WILDCARD' acts as a wildcard and finds any Zorro device. If your driver
+supports different types of boards, you can use a construct like:
+
+    struct zorro_dev *z = NULL;
+
+    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+	if (z->id != ZORRO_PROD_xxx1 && z->id != ZORRO_PROD_xxx2 && ...)
+	    continue;
+	if (!zorro_request_region(z->resource.start+MY_START, MY_SIZE,
+				  "My explanation"))
+	...
+    }
+
+
+3. Zorro Resources
+------------------
+
+Before you can access a Zorro device's registers, you have to make sure it's
+not yet in use. This is done using the I/O memory space resource management
+functions:
+
+    request_mem_region()
+    check_mem_region()		(deprecated)
+    release_mem_region()
+
+Shortcuts to claim the whole device's address space are provided as well:
+
+    zorro_request_device
+    zorro_check_device		(deprecated)
+    zorro_release_device
+
+
+4. Accessing the Zorro Address Space
+------------------------------------
+
+The address regions in the Zorro device resources are Zorro bus address
+regions. Due to the identity bus-physical address mapping on the Zorro bus,
+they are CPU physical addresses as well.
+
+The treatment of these regions depends on the type of Zorro space:
+
+  - Zorro II address space is always mapped and does not have to be mapped
+    explicitly using ioremap().
+    
+    Conversion from bus/physical Zorro II addresses to kernel virtual addresses
+    and vice versa is done using:
+
+	virt_addr = ZTWO_VADDR(bus_addr);
+	bus_addr = ZTWO_PADDR(virt_addr);
+
+  - Zorro III address space must be mapped explicitly using ioremap() first
+    before it can be accessed:
+ 
+	virt_addr = ioremap(bus_addr, size);
+	...
+	iounmap(virt_addr);
+
+
+5. Zorro Device Naming
+----------------------
+
+Since we think generic device naming is something for userspace (zorroutils),
+we don't keep a Zorro device name database in the kernel.
+However, device drivers are allowed to store the expansion board name in struct
+zorro_dev.
+
+
+6. References
+-------------
+
+linux/include/linux/zorro.h
+linux/include/linux/ioport.h
+linux/include/asm-m68k/io.h
+linux/include/asm-m68k/amigahw.h
+linux/include/asm-ppc/io.h
+linux/driver/zorro
+/proc/bus/zorro
+
diff -u --recursive --new-file v2.3.49/linux/Makefile linux/Makefile
--- v2.3.49/linux/Makefile	Thu Mar  2 14:36:22 2000
+++ linux/Makefile	Thu Mar  2 14:36:35 2000
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 49
+SUBLEVEL = 50
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.49/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.3.49/linux/arch/alpha/kernel/Makefile	Thu Mar  2 14:36:22 2000
+++ linux/arch/alpha/kernel/Makefile	Tue Mar  7 11:04:12 2000
@@ -132,7 +132,7 @@
 	./check_asm > $(TOPDIR)/include/asm-alpha/asm_offsets.h
 
 check_asm: check_asm.c
-	gcc -o $@ $< -I$(TOPDIR)/include -D__KERNEL__ -ffixed-8
+	$(HOSTCC) -o $@ $< $(CPPFLAGS) -ffixed-8
 
 clean::
 	rm -f check_asm
diff -u --recursive --new-file v2.3.49/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.49/linux/arch/alpha/kernel/osf_sys.c	Fri Jan 28 15:09:06 2000
+++ linux/arch/alpha/kernel/osf_sys.c	Mon Mar  6 15:49:21 2000
@@ -135,10 +135,8 @@
 {
 	int error;
 	struct file *file;
-	struct inode *inode;
 	struct osf_dirent_callback buf;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -149,18 +147,8 @@
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, osf_filldir);
-	up(&inode->i_sem);
+	lock_kernel();
+	error = vfs_readdir(file, osf_filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 
@@ -169,9 +157,9 @@
 		error = count - buf.count;
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.3.49/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.3.49/linux/arch/arm/Makefile	Fri Jan 21 18:19:15 2000
+++ linux/arch/arm/Makefile	Tue Mar  7 11:04:12 2000
@@ -100,7 +100,7 @@
  endif
 endif
 
-GCCLIB		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
+LIBGCC		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
 
 ifeq ($(CONFIG_ARCH_A5K),y)
 MACHINE		 = a5k
@@ -146,7 +146,7 @@
 SUBDIRS		+= arch/arm/kernel arch/arm/mm arch/arm/lib \
 		   arch/arm/special arch/arm/nwfpe
 CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
-LIBS		:= arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
+LIBS		:= arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC)
 DRIVERS		+= arch/arm/special/special.a
 
 ifeq ($(CONFIG_NWFPE),y)
diff -u --recursive --new-file v2.3.49/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
--- v2.3.49/linux/arch/arm/boot/compressed/Makefile	Thu Mar  2 14:36:22 2000
+++ linux/arch/arm/boot/compressed/Makefile	Tue Mar  7 11:04:12 2000
@@ -73,7 +73,7 @@
 all:		vmlinux
 
 vmlinux:	$(HEAD) $(OBJS) piggy.o vmlinux.lds
-		$(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux
+		$(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(LIBGCC) -o vmlinux
 
 $(HEAD): 	$(HEAD:.o=.S)
 		$(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S)
diff -u --recursive --new-file v2.3.49/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.3.49/linux/arch/i386/Makefile	Fri Jan 28 15:09:06 2000
+++ linux/arch/i386/Makefile	Tue Mar  7 11:04:12 2000
@@ -21,12 +21,10 @@
 LDFLAGS=-e stext
 LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS)
 
-CFLAGS_PIPE := -pipe
+CFLAGS += -pipe
 
 # only work around strength reduction bug(s) on older gcc versions
-CFLAGS_NSR  := $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo ""; else echo "-fno-strength-reduce"; fi)
-
-CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
+CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strength-reduce"; fi)
 
 # prevent gcc from keeping the stack 16 byte aligned
 CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
diff -u --recursive --new-file v2.3.49/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v2.3.49/linux/arch/i386/boot/compressed/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/i386/boot/compressed/Makefile	Tue Mar  7 11:04:12 2000
@@ -33,6 +33,9 @@
 head.o: head.S
 	$(CC) $(AFLAGS) -traditional -c head.S
 
+misc.o: misc.c
+	$(CC) $(CFLAGS) -c misc.c
+
 piggy.o:	$(SYSTEM)
 	tmppiggy=_tmp_$$$$piggy; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
diff -u --recursive --new-file v2.3.49/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.49/linux/arch/i386/config.in	Thu Mar  2 14:36:22 2000
+++ linux/arch/i386/config.in	Tue Mar  7 11:04:12 2000
@@ -47,6 +47,7 @@
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
+   define_bool CONFIG_X86_PGE y
 fi
 
 if [ "$CONFIG_DEVFS_FS" = "y" ]; then
diff -u --recursive --new-file v2.3.49/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.49/linux/arch/i386/defconfig	Thu Mar  2 14:36:22 2000
+++ linux/arch/i386/defconfig	Sun Mar  5 10:45:17 2000
@@ -76,6 +76,10 @@
 CONFIG_PM=y
 CONFIG_ACPI=y
 # CONFIG_APM is not set
+
+#
+# Parallel port support
+#
 # CONFIG_PARPORT is not set
 
 #
@@ -282,6 +286,7 @@
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_TULIP is not set
 # CONFIG_DGRS is not set
@@ -308,7 +313,7 @@
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring driver support
+# Token Ring devices
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
diff -u --recursive --new-file v2.3.49/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.49/linux/arch/i386/kernel/irq.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/i386/kernel/irq.c	Fri Mar  3 12:54:44 2000
@@ -199,13 +199,13 @@
 		printk(" %d",local_bh_count(i));
 
 	printk(" ]\nStack dumps:");
-	for(i=0;i< smp_num_cpus;i++) {
+	for(i = 0; i < smp_num_cpus; i++) {
 		unsigned long esp;
-		if(i==cpu)
+		if (i == cpu)
 			continue;
 		printk("\nCPU %d:",i);
 		esp = init_tss[i].esp0;
-		if(esp==NULL) {
+		if (!esp) {
 			/* tss->esp0 is set to NULL in cpu_init(),
 			 * it's initialized when the cpu returns to user
 			 * space. -- manfreds
diff -u --recursive --new-file v2.3.49/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.49/linux/arch/i386/mm/init.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/i386/mm/init.c	Fri Mar  3 12:57:16 2000
@@ -320,7 +320,7 @@
 		if (vaddr >= end)
 			break;
 #if CONFIG_X86_PAE
-		pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
+		pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 		set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
 #else
 		pmd = (pmd_t *)pgd;
diff -u --recursive --new-file v2.3.49/linux/arch/ia64/Makefile linux/arch/ia64/Makefile
--- v2.3.49/linux/arch/ia64/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/Makefile	Tue Mar  7 11:04:12 2000
@@ -88,7 +88,7 @@
 vmlinux: arch/$(ARCH)/vmlinux.lds
 
 arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE
-	gcc -D__ASSEMBLY__ -E -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \
+	$(CPP) -D__ASSEMBLY__ -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \
 		arch/$(ARCH)/vmlinux.lds.S > $@
 
 FORCE: ;
diff -u --recursive --new-file v2.3.49/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.3.49/linux/arch/mips/kernel/sysirix.c	Sat Feb 26 22:31:40 2000
+++ linux/arch/mips/kernel/sysirix.c	Mon Mar  6 15:49:21 2000
@@ -2025,12 +2025,10 @@
 asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
 {
 	struct file *file;
-	struct inode *inode;
 	struct irix_dirent32 *lastdirent;
 	struct irix_dirent32_callback buf;
 	int error;
 
-	lock_kernel();
 #ifdef DEBUG_GETDENTS
 	printk("[%s:%ld] ngetdents(%d, %p, %d, %p) ", current->comm,
 	       current->pid, fd, dirent, count, eob);
@@ -2040,26 +2038,14 @@
 	if (!file)
 		goto out;
 
-	inode = file->f_dentry->d_inode;
-	if (!inode)
-		goto out_putf;
+	lock_kernel();
 
 	buf.current_dir = (struct irix_dirent32 *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, irix_filldir32);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, irix_filldir32, &buf);
 	if (error < 0)
 		goto out_putf;
 	error = buf.error;
@@ -2081,9 +2067,9 @@
 	error = count - buf.count;
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -2134,12 +2120,10 @@
 asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
 {
 	struct file *file;
-	struct inode *inode;
 	struct irix_dirent64 *lastdirent;
 	struct irix_dirent64_callback buf;
 	int error;
 
-	lock_kernel();
 #ifdef DEBUG_GETDENTS
 	printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm,
 	       current->pid, fd, dirent, cnt);
@@ -2148,13 +2132,7 @@
 	if (!(file = fget(fd)))
 		goto out;
 
-	inode = file->f_dentry->d_inode;
-	if (!inode)
-		goto out_f;
-
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_f;
+	lock_kernel();
 
 	error = -EFAULT;
 	if(!access_ok(VERIFY_WRITE, dirent, cnt))
@@ -2168,9 +2146,7 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, irix_filldir64);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, irix_filldir64, &buf);
 	if (error < 0)
 		goto out_f;
 	lastdirent = buf.previous;
@@ -2185,21 +2161,19 @@
 	error = cnt - buf.count;
 
 out_f:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
 asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
 {
 	struct file *file;
-	struct inode *inode;
 	struct irix_dirent64 *lastdirent;
 	struct irix_dirent64_callback buf;
 	int error;
 
-	lock_kernel();
 #ifdef DEBUG_GETDENTS
 	printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm,
 	       current->pid, fd, dirent, cnt);
@@ -2208,13 +2182,7 @@
 	if (!(file = fget(fd)))
 		goto out;
 
-	inode = file->f_dentry->d_inode;
-	if (!inode)
-		goto out_f;
-
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_f;
+	lock_kernel();
 
 	error = -EFAULT;
 	if(!access_ok(VERIFY_WRITE, dirent, cnt) ||
@@ -2230,9 +2198,7 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, irix_filldir64);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, irix_filldir64, &buf);
 	if (error < 0)
 		goto out_f;
 	lastdirent = buf.previous;
@@ -2247,9 +2213,9 @@
 	error = cnt - buf.count;
 
 out_f:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig
--- v2.3.49/linux/arch/ppc/configs/common_defconfig	Sat Feb 26 22:31:41 2000
+++ linux/arch/ppc/configs/common_defconfig	Thu Mar  2 22:46:07 2000
@@ -92,7 +92,14 @@
 #
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# 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_CMD64X is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -194,6 +201,7 @@
 #
 # SCSI low-level drivers
 #
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
@@ -249,7 +257,6 @@
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
 CONFIG_SCSI_MAC53C94=y
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -266,6 +273,7 @@
 #
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
@@ -389,7 +397,7 @@
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
-CONFIG_FB_ATY128=y
+# CONFIG_FB_ATY128 is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -448,6 +456,7 @@
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -496,6 +505,8 @@
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_DABUSB is not set
 # CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
 
 #
 # USB HID
@@ -503,7 +514,7 @@
 # CONFIG_USB_HID is not set
 CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
-# CONFIG_USB_GRAPHIRE is not set
+# CONFIG_USB_WACOM is not set
 # CONFIG_USB_WMFORCE is not set
 CONFIG_INPUT_KEYBDEV=y
 CONFIG_INPUT_MOUSEDEV=y
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.49/linux/arch/ppc/defconfig	Sat Feb 26 22:31:41 2000
+++ linux/arch/ppc/defconfig	Thu Mar  2 22:46:07 2000
@@ -92,7 +92,14 @@
 #
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# 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_CMD64X is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -194,6 +201,7 @@
 #
 # SCSI low-level drivers
 #
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
@@ -249,7 +257,6 @@
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
 CONFIG_SCSI_MAC53C94=y
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -266,6 +273,7 @@
 #
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
@@ -389,7 +397,7 @@
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
-CONFIG_FB_ATY128=y
+# CONFIG_FB_ATY128 is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -448,6 +456,7 @@
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -496,6 +505,8 @@
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_DABUSB is not set
 # CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
 
 #
 # USB HID
@@ -503,7 +514,7 @@
 # CONFIG_USB_HID is not set
 CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
-# CONFIG_USB_GRAPHIRE is not set
+# CONFIG_USB_WACOM is not set
 # CONFIG_USB_WMFORCE is not set
 CONFIG_INPUT_KEYBDEV=y
 CONFIG_INPUT_MOUSEDEV=y
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.3.49/linux/arch/ppc/kernel/Makefile	Sat Feb 26 22:31:41 2000
+++ linux/arch/ppc/kernel/Makefile	Thu Mar  2 22:46:07 2000
@@ -98,7 +98,7 @@
   OX_OBJS += prep_setup.o
 endif
 ifeq ($(CONFIG_GEMINI),y)
-  O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o
+  O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o open_pic.o
 endif
 
 all: $(KHEAD) kernel.o
@@ -114,6 +114,8 @@
 		$(TOPDIR)/include/asm/ptrace.h
 	$(CC) $(CFLAGS) -S mk_defs.c
 	cp ppc_defs.head ppc_defs.h
+# for bk, this way we can write to the file even if it's not checked out
+	chmod u+w ppc_defs.h
 	grep '^#define' mk_defs.s >> ppc_defs.h
 	rm mk_defs.s
 
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- v2.3.49/linux/arch/ppc/kernel/feature.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/feature.c	Thu Mar  2 22:46:07 2000
@@ -154,6 +154,9 @@
 {
 	struct device_node *np;
 
+	if (_machine != _MACH_Pmac)
+		return;
+
 	np = find_devices("mac-io");
 	while (np != NULL) {
 		/* KeyLargo contains several (5 ?) FCR registers in mac-io,
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.49/linux/arch/ppc/kernel/head.S	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/head.S	Thu Mar  2 22:46:07 2000
@@ -222,7 +222,7 @@
 	mtspr	IBAT0L,r8
 	mtspr	IBAT0U,r11
 #if 0 /* Useful debug code, please leave in for now so I don't have to
-       * look at docs when I need to setup a BAT ;
+       * look at docs when I need to setup a BAT ...
        */
 	bl	setup_screen_bat
 #endif
@@ -256,6 +256,8 @@
  * prep needs the mmu to be turned on here, but pmac already has it on.
  * this shouldn't bother the pmac since it just gets turned on again
  * as we jump to our code at KERNELBASE. -- Cort
+ * Actually no, pmac doesn't have it on any more. BootX enters with MMU
+ * off, and in other cases, we now turn it off before changing BATs above.
  */
 turn_on_mmu:
 	mfmsr	r0
@@ -1423,6 +1425,7 @@
 	li	r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
 	mtspr	SRR0,r4
 	mtspr	SRR1,r3
+	SYNC
 	rfi
 /* Load up the kernel context */
 2:
@@ -1433,6 +1436,7 @@
 	tlbsync			/* ... on all CPUs */
 	sync
 #endif
+	
 	bl	load_up_mmu
 
 /* Set up for using our exception vectors */
@@ -1448,6 +1452,7 @@
 	ori	r3,r3,start_kernel@l
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
+	SYNC
 	rfi			/* enable MMU and jump to start_kernel */
 
 /*
@@ -1530,11 +1535,11 @@
 	li	r3,0
 	mtspr	DBAT1U,r3
 	mtspr	IBAT1U,r3
-	lis	r3, 0x9100
+	lis	r3, 0x8200
 	ori	r4,r3,0x2a
 	mtspr	DBAT1L,r4
 	mtspr	IBAT1L,r4
-	ori	r3,r3,(BL_8M<<2)|0x2	/* set up BAT registers for 604 */
+	ori	r3,r3,(BL_16M<<2)|0x2	/* set up BAT registers for 604 */
 	mtspr	DBAT1U,r3
 	mtspr	IBAT1U,r3
 	blr
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.49/linux/arch/ppc/kernel/irq.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/irq.c	Thu Mar  2 22:46:07 2000
@@ -45,7 +45,9 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
+#include <linux/proc_fs.h>
 
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/hydra.h>
 #include <asm/system.h>
@@ -611,3 +613,160 @@
 }
 #endif /* __SMP__ */
 
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff};
+
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08x\n", irq_affinity[(int)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+		unsigned long count, unsigned long *ret)
+{
+	unsigned char hexnum [HEX_DIGITS];
+	unsigned long value;
+	int i;
+
+	if (!count)
+		return -EINVAL;
+	if (count > HEX_DIGITS)
+		count = HEX_DIGITS;
+	if (copy_from_user(hexnum, buffer, count))
+		return -EFAULT;
+
+	/*
+	 * Parse the first 8 characters as a hex string, any non-hex char
+	 * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+	 */
+	value = 0;
+
+	for (i = 0; i < count; i++) {
+		unsigned int c = hexnum[i];
+
+		switch (c) {
+			case '0' ... '9': c -= '0'; break;
+			case 'a' ... 'f': c -= 'a'-10; break;
+			case 'A' ... 'F': c -= 'A'-10; break;
+		default:
+			goto out;
+		}
+		value = (value << 4) | c;
+	}
+out:
+	*ret = value;
+	return 0;
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	int irq = (int) data, full_count = count, err;
+	unsigned long new_value;
+
+	if (!irq_desc[irq].handler->set_affinity)
+		return -EIO;
+
+	err = parse_hex_value(buffer, count, &new_value);
+
+#if CONFIG_SMP
+	/*
+	 * Do not allow disabling IRQs completely - it's a too easy
+	 * way to make the system unusable accidentally :-) At least
+	 * one online CPU still has to be targeted.
+	 */
+	if (!(new_value & cpu_online_map))
+		return -EINVAL;
+#endif
+
+	irq_affinity[irq] = new_value;
+	irq_desc[irq].handler->set_affinity(irq, new_value);
+
+	return full_count;
+}
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	unsigned long *mask = (unsigned long *) data;
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	unsigned long *mask = (unsigned long *) data, full_count = count, err;
+	unsigned long new_value;
+
+	err = parse_hex_value(buffer, count, &new_value);
+	if (err)
+		return err;
+
+	*mask = new_value;
+	return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+	struct proc_dir_entry *entry;
+	char name [MAX_NAMELEN];
+
+	if (!root_irq_dir || (irq_desc[irq].handler == NULL))
+		return;
+
+	memset(name, 0, MAX_NAMELEN);
+	sprintf(name, "%d", irq);
+
+	/* create /proc/irq/1234 */
+	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+	/* create /proc/irq/1234/smp_affinity */
+	entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+
+	entry->nlink = 1;
+	entry->data = (void *)irq;
+	entry->read_proc = irq_affinity_read_proc;
+	entry->write_proc = irq_affinity_write_proc;
+
+	smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+	struct proc_dir_entry *entry;
+	int i;
+
+	/* create /proc/irq */
+	root_irq_dir = proc_mkdir("irq", 0);
+
+	/* create /proc/irq/prof_cpu_mask */
+	entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+
+	entry->nlink = 1;
+	entry->data = (void *)&prof_cpu_mask;
+	entry->read_proc = prof_cpu_mask_read_proc;
+	entry->write_proc = prof_cpu_mask_write_proc;
+
+	/*
+	 * Create entries for all existing IRQs.
+	 */
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].handler == NULL)
+			continue;
+		register_irq_proc(i);
+	}
+}
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.49/linux/arch/ppc/kernel/pci.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/pci.c	Thu Mar  2 22:46:07 2000
@@ -131,11 +131,6 @@
 	return str;
 }
 
-int pcibios_assign_resource(struct pci_dev *pdev, int resource)
-{
-	return 0;
-}
-
 /* the next two are stolen from the alpha port... */
 void __init
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
@@ -187,50 +182,5 @@
 		       dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
-	return 0;
-}
-
-/*
- * Assign new address to PCI resource.  We hope our resource information
- * is complete.  We don't re-assign resources unless we are
- * forced to do so.
- *
- * Expects start=0, end=size-1, flags=resource type.
- */
-
-int pci_assign_resource(struct pci_dev *dev, int i)
-{
-	struct resource *r = &dev->resource[i];
-	struct resource *pr = pci_find_parent_resource(dev, r);
-	unsigned long size = r->end + 1;
-	u32 new, check;
-
-	if (!pr) {
-		printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
-		return -EINVAL;
-	}
-	if (r->flags & IORESOURCE_IO) {
-		if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) {
-			printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
-			return -EBUSY;
-		}
-	} else {
-		if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) {
-			printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
-			return -EBUSY;
-		}
-	}
-	if (i < 6) {
-		int reg = PCI_BASE_ADDRESS_0 + 4*i;
-		new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
-		pci_write_config_dword(dev, reg, new);
-		pci_read_config_dword(dev, reg, &check);
-		if (new != check)
-			printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
-	} else if (i == PCI_ROM_RESOURCE) {
-		r->flags |= PCI_ROM_ADDRESS_ENABLE;
-		pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
-	}
-	printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
 	return 0;
 }
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.3.49/linux/arch/ppc/kernel/pmac_pic.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/pmac_pic.c	Thu Mar  2 22:46:07 2000
@@ -10,6 +10,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/prom.h>
+#include <asm/pci-bridge.h>
 #include "pmac_pic.h"
 
 /* pmac */struct pmac_irq_hw {
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.49/linux/arch/ppc/kernel/pmac_setup.c	Sun Feb 13 19:29:03 2000
+++ linux/arch/ppc/kernel/pmac_setup.c	Thu Mar  2 22:46:07 2000
@@ -283,8 +283,6 @@
 			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
 				? "enabled" : "disabled");
 
-	feature_init();
-
 #ifdef CONFIG_KGDB
 	zs_kgdb_hook(0);
 #endif
@@ -325,14 +323,15 @@
 	    || p2pbridge->parent == NULL
 	    || strcmp(p2pbridge->parent->name, "pci") != 0)
 		return;
-
 	if (pci_device_loc(p2pbridge, &bus, &devfn) < 0)
 		return;
-
-	pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
+	if (ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) {
+		printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+		return;
+	}
 	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
-	pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val);
-	pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
+	ppc_md.pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val);
+	ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
 }
 
 static void __init ohare_init(void)
@@ -703,8 +702,8 @@
 {
 	if (disp_bi == 0)
 		return;
-	drawstring(s);
-	drawchar('\n');
+	prom_drawstring(s);
+	prom_drawchar('\n');
 }
 #endif CONFIG_BOOTX_TEXT
 
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- v2.3.49/linux/arch/ppc/kernel/ppc_htab.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/ppc_htab.c	Thu Mar  2 22:46:07 2000
@@ -44,12 +44,6 @@
 extern unsigned long pte_misses;
 extern unsigned long pte_errors;
 
-struct file_operations ppc_htab_operations = {
-	llseek:		ppc_htab_lseek,
-	read:		ppc_htab_read,
-	write:		ppc_htab_write,
-};
-
 /* these will go into processor.h when I'm done debugging -- Cort */
 #define MMCR0 952
 #define MMCR0_PMC1_CYCLES (0x1<<7)
@@ -62,6 +56,12 @@
 
 #define PMC1 953
 #define PMC2 954
+
+struct file_operations ppc_htab_operations = {
+        llseek:         ppc_htab_lseek,
+        read:           ppc_htab_read,
+        write:          ppc_htab_write,
+};
 
 char *pmc1_lookup(unsigned long mmcr0)
 {
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.49/linux/arch/ppc/kernel/prom.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/prom.c	Thu Mar  2 22:46:07 2000
@@ -114,9 +114,9 @@
 static void clearscreen(void);
 static void flushscreen(void);
 
-void drawchar(char c);
-void drawstring(const char *c);
-static void drawhex(unsigned long v);
+void prom_drawchar(char c);
+void prom_drawstring(const char *c);
+void prom_drawhex(unsigned long v);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
@@ -134,6 +134,8 @@
 
 static unsigned char vga_font[cmapsz];
 
+int bootx_text_mapped = 1;
+
 #endif /* CONFIG_BOOTX_TEXT */
 
 
@@ -257,7 +259,7 @@
 	{
 #ifdef CONFIG_BOOTX_TEXT
 		if (RELOC(disp_bi) != 0)
-			drawstring(msg);
+			prom_drawstring(msg);
 #endif
 		return;
 	}		
@@ -385,6 +387,7 @@
 #ifdef CONFIG_BOOTX_TEXT
 		prom_print(RELOC("booting...\n"));
 		flushscreen();
+		RELOC(bootx_text_mapped) = 0;
 #endif
 		return phys;
 	}
@@ -633,6 +636,7 @@
 		prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
 		prom_print(RELOC("booting...\n"));
 	}
+	RELOC(bootx_text_mapped) = 0;
 #endif
 
 	return phys;
@@ -648,28 +652,30 @@
 	
 	prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
 	prom_print(RELOC("\nstarted at       : 0x"));
-	drawhex(phys);
+	prom_drawhex(phys);
 	prom_print(RELOC("\nlinked at        : 0x"));
-	drawhex(KERNELBASE);
+	prom_drawhex(KERNELBASE);
 	prom_print(RELOC("\nframe buffer at  : 0x"));
-	drawhex((unsigned long)bi->dispDeviceBase);
+	prom_drawhex((unsigned long)bi->dispDeviceBase);
 	prom_print(RELOC(" (phys), 0x"));
-	drawhex((unsigned long)bi->logicalDisplayBase);
+	prom_drawhex((unsigned long)bi->logicalDisplayBase);
 	prom_print(RELOC(" (log)"));
+	prom_print(RELOC("\nklimit           : 0x"));
+	prom_drawhex(RELOC(klimit));
 	prom_print(RELOC("\nMSR              : 0x"));
 	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
-	drawhex(flags);
+	prom_drawhex(flags);
 	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
 	pvr >>= 16;
 	if (pvr > 1) {
 	    prom_print(RELOC("\nHID0             : 0x"));
 	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
-	    drawhex(flags);
+	    prom_drawhex(flags);
 	}
 	if (pvr == 8 || pvr == 12) {
 	    prom_print(RELOC("\nICTC             : 0x"));
 	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
-	    drawhex(flags);
+	    prom_drawhex(flags);
 	}
 	prom_print(RELOC("\n\n"));
 }
@@ -807,13 +813,18 @@
 	
 	prom_print(RELOC("Initializing fake screen\n"));
 
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width));
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height));
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"),
+		  &width, sizeof(width));
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"),
+		  &height, sizeof(height));
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"),
+		  &depth, sizeof(depth));
 	pitch = width * ((depth + 7) / 8);
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"),
+		  &pitch, sizeof(pitch));
 	address = 0;
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"),
+		  &address, sizeof(address));
 	if (address == 0) {
 		prom_print(RELOC("Failed to get address\n"));
 		return;
@@ -837,7 +848,6 @@
 	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
 	bi->dispDeviceRect[2] = width;
 	bi->dispDeviceRect[3] = height;
-	RELOC(disp_bi) = 0;
 }
 #endif
 
@@ -1844,6 +1854,7 @@
 	disp_bi->logicalDisplayBase =
 		ioremap((unsigned long) disp_bi->dispDeviceBase,
 			disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
+	bootx_text_mapped = 1;
 }
 
 /* Calc the base address of a given point (x,y) */
@@ -1940,11 +1951,14 @@
 
 __pmac
 void
-drawchar(char c)
+prom_drawchar(char c)
 {
 	unsigned long offset = reloc_offset();
 	int cline = 0, x;
 
+	if (!RELOC(bootx_text_mapped))
+		return;
+
 	switch (c) {
 	case '\b':
 		if (RELOC(g_loc_X) > 0)
@@ -1988,27 +2002,33 @@
 
 __pmac
 void
-drawstring(const char *c)
+prom_drawstring(const char *c)
 {
+	unsigned long offset	= reloc_offset();
+
+	if (!RELOC(bootx_text_mapped))
+		return;
 	while (*c)
-		drawchar(*c++);
+		prom_drawchar(*c++);
 }
 
 __pmac
-static void
-drawhex(unsigned long v)
+void
+prom_drawhex(unsigned long v)
 {
 	static char hex_table[] = "0123456789abcdef";
 	unsigned long offset	= reloc_offset();
 	
-	drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
-	drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
+	if (!RELOC(bootx_text_mapped))
+		return;
+	prom_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
+	prom_drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
 }
 
 
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.49/linux/arch/ppc/kernel/setup.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/kernel/setup.c	Thu Mar  2 22:46:07 2000
@@ -29,6 +29,7 @@
 #endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
+#include <asm/feature.h>
 #ifdef CONFIG_OAK
 #include "oak_setup.h"
 #endif /* CONFIG_OAK */
@@ -417,7 +418,7 @@
 		 unsigned long r6, unsigned long r7)
 {
 	parse_bootinfo();
-
+	
 	if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
 	
 #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
@@ -687,6 +688,7 @@
 
 	ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
+	paging_init();
 }
 
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
@@ -733,12 +735,12 @@
 	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
 	id->eide_pio       = __le16_to_cpu(id->eide_pio);
 	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i=0; i<2 i++)
+	for (i=0; i<2; i++)
 		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i=0; i<4 i++)
+        for (i=0; i<4; i++)
                 id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
 	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i=0; i<4 i++)
+	for (i=0; i<4; i++)
 		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
 	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
 	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.49/linux/arch/ppc/mm/init.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/mm/init.c	Thu Mar  2 22:46:07 2000
@@ -961,8 +961,9 @@
 		}
 #endif
 #if 0
-		setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE);
-		disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase;
+// This is bogus, BAT must be aligned.
+//		setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE);
+//		disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase;
 #endif		
 		ioremap_base = 0xf0000000;
 		break;
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.3.49/linux/arch/ppc/xmon/start.c	Sun Feb 13 19:29:03 2000
+++ linux/arch/ppc/xmon/start.c	Thu Mar  2 22:46:07 2000
@@ -17,12 +17,12 @@
 static volatile unsigned char *sccc, *sccd;
 unsigned long TXRDY, RXRDY;
 extern void xmon_printf(const char *fmt, ...);
-extern void drawchar(char);
-extern void drawstring(const char *str);
+extern void prom_drawchar(char);
+extern void prom_drawstring(const char *str);
 static int xmon_expect(const char *str, unsigned int timeout);
 
 static int console = 0;
-static int use_screen = 0;
+static int use_screen = 1; /* default */
 static int via_modem = 0;
 static int xmon_use_sccb = 0;
 static struct device_node *macio_node;
@@ -48,6 +48,8 @@
 {
 	volatile unsigned char *base;
 
+	use_screen = 0;
+	
 	if ( _machine == _MACH_Pmac )
 	{
 		struct device_node *np;
@@ -58,7 +60,7 @@
 		/* needs to be hacked if xmon_printk is to be used
  		   from within find_via_pmu() */
 		if (!via_modem && disp_bi && find_via_pmu()) {
-			drawstring("xmon uses screen and keyboard\n");
+			prom_drawstring("xmon uses screen and keyboard\n");
 			use_screen = 1;
 			return;
 		}
@@ -122,7 +124,7 @@
 	if (use_screen) {
 		/* write it on the screen */
 		for (i = 0; i < nb; ++i)
-			drawchar(*p++);
+			prom_drawchar(*p++);
 		return nb;
 	}
 #endif
@@ -142,6 +144,7 @@
 			ct = 1;
 			--i;
 		} else {
+			prom_drawchar(c);
 			if (console)
 				printk("%c", c);
 			ct = 0;
@@ -187,15 +190,15 @@
 		do {
 			if (--t < 0) {
 				on = 1 - on;
-				drawchar(on? 0xdb: 0x20);
-				drawchar('\b');
+				prom_drawchar(on? 0xdb: 0x20);
+				prom_drawchar('\b');
 				t = 200000;
 			}
 			pmu_poll();
 		} while (xmon_pmu_keycode == -1);
 		k = xmon_pmu_keycode;
 		if (on)
-			drawstring(" \b");
+			prom_drawstring(" \b");
 
 		/* test for shift keys */
 		if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
@@ -284,6 +287,8 @@
 	{
 		int i, x;
 
+		if (macio_node != 0)
+			feature_set(macio_node, FEATURE_Serial_enable);
 		if (via_modem && macio_node != 0) {
 			unsigned int t0;
 
@@ -399,15 +404,12 @@
 		for (;;) {
 			c = xmon_read_poll();
 			if (c == -1) {
-				if (readtb() - t0 > timeout) {
-					printk("timeout\n");
+				if (readtb() - t0 > timeout)
 					return 0;
-				}
 				continue;
 			}
 			if (c == '\n')
 				break;
-			printk("%c", c);
 			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
 				*lineptr++ = c;
 		}
diff -u --recursive --new-file v2.3.49/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
--- v2.3.49/linux/arch/ppc/xmon/xmon.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/ppc/xmon/xmon.c	Thu Mar  2 22:46:07 2000
@@ -119,7 +119,8 @@
 xmon(struct pt_regs *excp)
 {
 	struct pt_regs regs;
-	int msr, cmd;
+	int msr, cmd, i;
+	unsigned *sp;
 
 	if (excp == NULL) {
 		asm volatile ("stw	0,0(%0)\n\
@@ -135,6 +136,29 @@
 		excp = &regs;
 	}
 
+	prom_drawstring("xmon pc="); prom_drawhex(excp->nip);
+	prom_drawstring(" lr="); prom_drawhex(excp->link);
+	prom_drawstring(" msr="); prom_drawhex(excp->msr);
+	prom_drawstring(" trap="); prom_drawhex(excp->trap);
+	prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]);
+	sp = &excp->gpr[0];
+	for (i = 0; i < 32; ++i) {
+		if ((i & 7) == 0)
+			prom_drawstring("\n");
+		prom_drawstring(" ");
+		prom_drawhex(sp[i]);
+	}
+	sp = (unsigned *) excp->gpr[1];
+	for (i = 0; i < 64; ++i) {
+		if ((i & 7) == 0) {
+			prom_drawstring("\n");
+			prom_drawhex(sp);
+			prom_drawstring(" ");
+		}
+		prom_drawstring(" ");
+		prom_drawhex(sp[i]);
+	}
+	prom_drawstring("\n");
 	msr = get_msr();
 	set_msr(msr & ~0x8000);	/* disable interrupts */
 	remove_bpts();
@@ -521,7 +545,7 @@
 excprint(struct pt_regs *fp)
 {
 	printf("vector: %x at pc = %x %s",
-	       fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/"");
+	       fp->trap, fp->nip, pretty_lookup_name(fp->nip));
 	printf(", msr = %x, sp = %x [%x]\n",
 	       fp->msr, fp->gpr[1], fp);
 	if (fp->trap == 0x300 || fp->trap == 0x600)
@@ -1390,6 +1414,10 @@
 	if ( !sysmap || !sysmap_size )
 		return NULL;
 	
+	/* adjust if addr is relative to kernelbase */
+	if ( addr < PAGE_OFFSET )
+		addr += PAGE_OFFSET;
+
 	cmp = simple_strtoul(c, &c, 8);
 	strcpy( last, strsep( &c, "\n"));
 	while ( c < (sysmap+sysmap_size) )
diff -u --recursive --new-file v2.3.49/linux/arch/sh/Makefile linux/arch/sh/Makefile
--- v2.3.49/linux/arch/sh/Makefile	Fri Oct 22 13:21:45 1999
+++ linux/arch/sh/Makefile	Tue Mar  7 11:04:12 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1 1999/09/18 16:55:51 gniibe Exp gniibe $
+# $Id: Makefile,v 1.2 1999/12/23 12:13:53 gniibe Exp gniibe $
 #
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
@@ -15,21 +15,21 @@
 #
 # Select the object file format to substitute into the linker script.
 #
-tool-prefix	= sh-elf
+tool-prefix	= sh-linux-gnu-
 
 ifdef CONFIG_LITTLE_ENDIAN
 CFLAGS		+= -ml
 AFLAGS		+= -ml
 # LINKFLAGS	+= -EL
 LDFLAGS		:= -EL
-
-LD	=$(CROSS_COMPILE)ld $(LDFLAGS)
-
 endif
 
-ifdef CONFIG_CROSSCOMPILE
+# ifdef CONFIG_CROSSCOMPILE
 CROSS_COMPILE  = $(tool-prefix)
-endif
+# endif
+
+LD	=$(CROSS_COMPILE)ld $(LDFLAGS)
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 
 MODFLAGS	+=
 
@@ -51,7 +51,7 @@
 # none has been choosen above.
 #
 LINKSCRIPT    = arch/sh/vmlinux.lds
-LINKFLAGS     += -T $(word 1,$(LINKSCRIPT)) -e __stext
+LINKFLAGS     += -T $(word 1,$(LINKSCRIPT)) -e _stext
 
 ifdef LOADADDR
 LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
@@ -73,7 +73,7 @@
 vmlinux: arch/sh/vmlinux.lds
 
 arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE
-	gcc -E -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
+	$(CPP) -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
 
 FORCE: ;
 
diff -u --recursive --new-file v2.3.49/linux/arch/sh/boot/Makefile linux/arch/sh/boot/Makefile
--- v2.3.49/linux/arch/sh/boot/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/boot/Makefile	Sun Mar  5 09:33:55 2000
@@ -1,5 +1,5 @@
 #
-# arch/mips/boot/Makefile
+# arch/sh/boot/Makefile
 #
 # 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
diff -u --recursive --new-file v2.3.49/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.3.49/linux/arch/sh/config.in	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/config.in	Sun Mar  5 09:33:55 2000
@@ -4,6 +4,10 @@
 #
 mainmenu_name "Linux/SuperH Kernel Configuration"
 
+define_bool CONFIG_SUPERH y
+
+define_bool CONFIG_UID16 y
+
 mainmenu_option next_comment
 comment 'Code maturity level options'
 bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
@@ -29,7 +33,6 @@
 fi
 bool 'Little Endian' CONFIG_LITTLE_ENDIAN
 hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
-bool 'Use SH CPU internal real time clock' CONFIG_SH_CPU_RTC
 endmenu
 
 mainmenu_option next_comment
@@ -43,63 +46,139 @@
 
 mainmenu_option next_comment
 comment 'General setup'
+
 bool 'Networking support' CONFIG_NET
+
+bool 'Directy Connected Compact Flash support' CONFIG_CF_ENABLER
+
+bool 'PCI support' CONFIG_PCI
+if [ "$CONFIG_PCI" = "y" ]; then
+   choice '  PCI access mode' \
+	"BIOS		CONFIG_PCI_GOBIOS	\
+	 Direct		CONFIG_PCI_GODIRECT	\
+	 Any		CONFIG_PCI_GOANY"	Any
+   if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+      define_bool CONFIG_PCI_BIOS y
+   fi
+   if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+      define_bool CONFIG_PCI_DIRECT y
+   fi
+fi
+
+source drivers/pci/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+   source drivers/pcmcia/Config.in
+fi
+
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
-
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
 	 A.OUT		CONFIG_KCORE_AOUT" ELF
 fi
-
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-endmenu
 
-mainmenu_option next_comment
-comment 'Character devices'
-define_bool CONFIG_SERIAL n
-define_bool CONFIG_SERIAL_CONSOLE y
-bool 'SuperH SCI support' CONFIG_SH_SCI_SERIAL
-bool 'SuperH SCIF support' CONFIG_SH_SCIF_SERIAL
+source drivers/parport/Config.in
+
 endmenu
 
-mainmenu_option next_comment
-comment 'Floppy, IDE, and other block devices'
+source drivers/block/Config.in
 
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
-   bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
 fi
 
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
 endmenu
 
+source drivers/ieee1394/Config.in
+
 if [ "$CONFIG_NET" = "y" ]; then
-   source net/Config.in
    mainmenu_option next_comment
-   comment 'Network device drivers'
+   comment 'Network device support'
+
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
       source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
+   fi
    endmenu
 fi
 
 mainmenu_option next_comment
+comment 'Character devices'
+
+bool 'Virtual terminal' CONFIG_VT
+if [ "$CONFIG_VT" = "y" ]; then
+   bool '  Support for console on virtual terminal' CONFIG_VT_CONSOLE
+fi
+
+tristate 'Serial support' CONFIG_SERIAL
+if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_SERIAL" = "m" ]; then
+   choice 'Serial interface type' \
+      "SCI  CONFIG_SH_SCI_SERIAL \
+       SCIF CONFIG_SH_SCIF_SERIAL"
+fi
+if [ "$CONFIG_SERIAL" = "y" ]; then
+   bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
 comment 'Unix 98 PTY support'
 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
+if [ "$CONFIG_PARPORT" != "n" ]; then
+   dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+   if [ "$CONFIG_PRINTER" != "n" ]; then
+      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
 endmenu
 
+if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+   source drivers/char/pcmcia/Config.in
+fi
+
+source drivers/misc/Config.in
+
 source fs/Config.in
 
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   bool 'VGA text console' CONFIG_VGA_CONSOLE
+   bool 'Video mode selection support' CONFIG_VIDEO_SELECT
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
+      source drivers/video/Config.in
+   fi
+   endmenu
+fi
+
+
 mainmenu_option next_comment
-comment 'Watchdog'
+comment 'Sound'
 
-tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source drivers/sound/Config.in
+fi
 endmenu
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.3.49/linux/arch/sh/defconfig linux/arch/sh/defconfig
--- v2.3.49/linux/arch/sh/defconfig	Tue Dec 14 01:27:23 1999
+++ linux/arch/sh/defconfig	Sun Mar  5 09:33:55 2000
@@ -1,6 +1,8 @@
 #
 # Automatically generated make config: don't edit
 #
+CONFIG_SUPERH=y
+CONFIG_UID16=y
 
 #
 # Code maturity level options
@@ -17,7 +19,6 @@
 # CONFIG_CPU_SH4 is not set
 CONFIG_LITTLE_ENDIAN=y
 CONFIG_MEMORY_START=0c000000
-CONFIG_SH_CPU_RTC=y
 
 #
 # Loadable module support
@@ -28,6 +29,9 @@
 # General setup
 #
 # CONFIG_NET is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_PCI is not set
+# CONFIG_HOTPLUG is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
@@ -35,22 +39,56 @@
 # CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PARPORT is not set
 
 #
-# Character devices
+# Block devices
 #
-# CONFIG_SERIAL is not set
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_SH_SCI_SERIAL=y
-# CONFIG_SH_SCIF_SERIAL is not set
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
 
 #
-# Floppy, IDE, and other block devices
+# IDE chipset support/bugfixes
 #
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SH_SCI_SERIAL=y
+# CONFIG_SH_SCIF_SERIAL is not set
+CONFIG_SERIAL_CONSOLE=y
 
 #
 # Unix 98 PTY support
@@ -58,16 +96,20 @@
 # CONFIG_UNIX98_PTYS is not set
 
 #
+# Misc devices
+#
+
+#
 # Filesystems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
 # CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
 # CONFIG_FAT_FS is not set
+# CONFIG_CRAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -75,6 +117,7 @@
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
@@ -82,14 +125,12 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
-# Watchdog
+# Sound
 #
-# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SOUND is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile
--- v2.3.49/linux/arch/sh/kernel/Makefile	Fri Oct 22 13:21:45 1999
+++ linux/arch/sh/kernel/Makefile	Sun Mar  5 09:33:55 2000
@@ -11,9 +11,18 @@
 
 O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o irq_onchip.o \
-            ptrace.o setup.o time.o sys_sh.o semaphore.o
+            ptrace.o setup.o time.o sys_sh.o semaphore.o pci-sh.o \
+	    irq_imask.o
 OX_OBJS  := sh_ksyms.o
 MX_OBJS  :=
+
+ifdef CONFIG_CF_ENABLER
+O_OBJS += cf-enabler.o
+endif
+
+ifdef CONFIG_CPU_SH4
+O_OBJS += fpu.o
+endif
 
 all: kernel.o head.o init_task.o
 
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/cf-enabler.c linux/arch/sh/kernel/cf-enabler.c
--- v2.3.49/linux/arch/sh/kernel/cf-enabler.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/cf-enabler.c	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,30 @@
+/* $Id: cf-enabler.c,v 1.2 1999/12/20 10:14:40 gniibe Exp $
+ *
+ *  linux/drivers/block/cf-enabler.c
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *
+ *  Enable the CF configuration.
+ */
+
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define CF_CIS_BASE	0xb8000000
+/*
+ * 0xB8000000 : Attribute
+ * 0xB8001000 : Common Memory
+ * 0xBA000000 : I/O
+ */
+
+int __init cf_init(void)
+{
+	outw(0x0042, CF_CIS_BASE+0x0200);
+	make_imask_irq(14);
+	disable_irq(14);
+	return 0;
+}
+
+__initcall (cf_init);
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- v2.3.49/linux/arch/sh/kernel/entry.S	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/kernel/entry.S	Sun Mar  5 09:33:55 2000
@@ -1,8 +1,8 @@
-/* $Id: entry.S,v 1.19 1999/10/31 13:19:35 gniibe Exp gniibe $
+/* $Id: entry.S,v 1.55 2000/03/05 01:48:58 gniibe Exp $
  *
  *  linux/arch/sh/entry.S
  *
- *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 1999, 2000  Niibe Yutaka
  *
  * 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
@@ -54,7 +54,8 @@
 addr_limit	= 12
 need_resched	= 20
 
-PF_TRACESYS  = 0x20
+PF_TRACESYS  = 0x00000020
+PF_USEDFPU   = 0x00100000
 
 ENOSYS = 38
 
@@ -207,37 +208,10 @@
 1:	.long	SYMBOL_NAME(do_exception_error)
 2:	.long	0xefffffff	! BL=0
 
-reschedule:
-	mova	SYMBOL_NAME(ret_from_syscall),r0
-	mov.l	1f,r1
-	jmp	@r1
-	 lds	r0,pr
-	.balign	4
-1:	.long	SYMBOL_NAME(schedule)
-
 badsys:	mov	#-ENOSYS,r0
 	rts			! go to ret_from_syscall..
 	 mov.l	r0,@(R0,r15)
 
-signal_return:
-	! We can reach here from an interrupt handler,
-	! so, we need to unblock interrupt.
-	/*  STI */
-	mov.l	1f,r1
-	stc	sr,r0
-	and	r1,r0
-	ldc	r0,sr
-	!
-	mov	r15,r4
-	mov	#0,r5
-	mov.l	2f,r1
-	mova	restore_all,r0
-	jmp	@r1
-	 lds	r0,pr
-	.balign	4
-1:	.long	0xefffffff		! BL=0
-2:	.long	SYMBOL_NAME(do_signal)
-
 !
 !
 !
@@ -274,7 +248,7 @@
 	ldc	r2,sr
 	!
 	mov.l	__n_sys,r1
-	cmp/ge	r1,r0
+	cmp/hs	r1,r0
 	bt/s	badsys
 	 mov	r0,r2
 	!
@@ -329,6 +303,9 @@
 3:	.long	SYMBOL_NAME(syscall_trace)
 2:	.long	0xefffffff	! BL=0
 1:	.long	TRA
+__n_sys:	.long	NR_syscalls
+__sct:		.long	SYMBOL_NAME(sys_call_table)
+__tsk_flags:	.long	flags-8192	! offset from stackbase to tsk->flags
 led:	.long	0xa8000000	! For my board -- gN
 
 	.section	.fixup,"ax"
@@ -343,30 +320,57 @@
 	.long	8b,fixup_syscall_argerr
 .previous
 
+reschedule:
+	mova	SYMBOL_NAME(ret_from_syscall),r0
+	mov.l	1f,r1
+	jmp	@r1
+	 lds	r0,pr
+	.balign	4
+1:	.long	SYMBOL_NAME(schedule)
 
 ENTRY(ret_from_irq)
-	mov.l	@(SR,r15),r0	! get original stack
+	mov.l	@(SR,r15),r0	! get status register
 	shll	r0
 	shll	r0		! kernel space?
 	bt	restore_all	! Yes, it's from kernel, go back soon
-	! XXX: Is it better to run through bottom half?
-	! In such a case, we should go "ret_from_syscall" instead
+	! STI
+	mov.l	1f, $r1
+	stc	$sr, $r2
+	and	$r1, $r2
+	ldc	$r2, $sr
+	!
 	bra	ret_with_reschedule
 	 nop
 
+ENTRY(ret_from_exception)
+	mov.l	@(SR,r15),r0	! get status register
+	shll	r0
+	shll	r0		! kernel space?
+	bt	restore_all	! Yes, it's from kernel, go back soon
+	! STI
+	mov.l	1f, $r1
+	stc	$sr, $r2
+	and	$r1, $r2
+	ldc	$r2, $sr
+	!
+	bra	ret_from_syscall
+	 nop
+	.balign	4
+1:	.long	0xefffffff	! BL=0
+
+	.balign 4
 ret:	add	r8,r15		! pop off the arguments
 	mov.l	r0,@(R0,r15)	! save the return value
 	/* fall through */
 
 ENTRY(ret_from_syscall)
-	mov.l	__bh_mask,r0
+	mov.l	__softirq_state,r0
 	mov.l	@r0,r1
-	mov.l	__bh_active,r0
-	mov.l	@r0,r2
+	mov.l	@(4,r0),r2
 	tst	r2,r1
 	bt	ret_with_reschedule
-handle_bottom_half:
-	mov.l	__dbh,r0
+handle_softirq:
+	mov.l	__do_softirq,r0
 	jsr	@r0
 	 nop
 ret_with_reschedule:
@@ -378,11 +382,44 @@
 	bf	reschedule
 	mov.l	@(sigpending,r1),r0
 	tst	#0xff,r0
-	bf	signal_return
-	!
+	bt	restore_all
+signal_return:
+	mov	r15,r4
+	mov	#0,r5
+	mov.l	__do_signal,r1
+	mova	restore_all,r0
+	jmp	@r1
+	 lds	r0,pr
+	.balign	4
+__do_signal:
+	.long	SYMBOL_NAME(do_signal)
+__softirq_state:
+	.long	SYMBOL_NAME(softirq_state)
+__do_softirq:
+	.long	SYMBOL_NAME(do_softirq)
+__minus8192:
+	.long	-8192		! offset from stackbase to tsk
+
+	.balign 4
 restore_all:
-	add	#4,r15		! skip syscall number
-	mov.l	@r15+,r11	! SSR
+#if defined(__SH4__)
+	mov.l	__fpu_prepare_fd, $r1
+	jsr	@$r1
+	 stc	$sr, $r4
+#endif
+	add	#4,r15		! Skip syscall number
+	mov.l	@r15+,r11	! Got SSR into R11
+#if defined(__SH4__)
+	mov	$r11, $r12
+#endif
+	!
+	mov.l	1f,r1
+	stc	sr,r0
+	and	r1,r0		! Get IMASK+FD
+	mov.l	2f,r1
+	and	r1,r11
+	or	r0,r11		! Inherit the IMASK+FD value of SR
+	!
 	mov.l	@r15+,r10	! original stack
 	mov.l	@r15+,r0
 	mov.l	@r15+,r1
@@ -398,6 +435,9 @@
 	ldc	r14,sr			! here, change the register bank
 	mov	r10,k0
 	mov	r11,k1
+#if defined(__SH4__)
+	mov	$r12, $k2
+#endif
 	mov.l	@r15+,r8
 	mov.l	@r15+,r9
 	mov.l	@r15+,r10
@@ -410,21 +450,69 @@
 	lds.l	@r15+,macl
 	lds.l	@r15+,pr
 	ldc.l	@r15+,spc
-	mov	k0,r15
 	ldc	k1,ssr
+#if defined(__SH4__)
+	shll	$k1
+	shll	$k1
+	bf	9f		! user mode
+	/* Kernel to kernel transition */
+	mov.l	3f, $k1
+	tst	$k1, $k2
+	bf	9f		! it hadn't FPU
+	! Kernel to kernel and FPU was used
+	! There's the case we don't get FPU now
+	stc	$sr, $k2
+	tst	$k1, $k2
+	bt	7f
+	! We need to grab FPU here
+	xor	$k1, $k2
+	ldc	$k2, $sr		! Grab FPU
+	mov.l	__init_task_flags, $k1
+	mov.l	@$k1, $k2
+	mov.l	__PF_USEDFPU, $k1
+	or	$k1, $k2
+	mov.l	__init_task_flags, $k1
+	mov.l	$k2, @$k1		! Set init_task.flags |= PF_USEDFPU
+	!
+	! Restoring FPU...
+	!
+7:	fmov.s	@$r15+, $fr0
+	fmov.s	@$r15+, $fr1
+	fmov.s	@$r15+, $fr2
+	fmov.s	@$r15+, $fr3
+	fmov.s	@$r15+, $fr4
+	fmov.s	@$r15+, $fr5
+	fmov.s	@$r15+, $fr6
+	fmov.s	@$r15+, $fr7
+	fmov.s	@$r15+, $fr8
+	fmov.s	@$r15+, $fr9
+	fmov.s	@$r15+, $fr10
+	fmov.s	@$r15+, $fr11
+	fmov.s	@$r15+, $fr12
+	fmov.s	@$r15+, $fr13
+	fmov.s	@$r15+, $fr14
+	fmov.s	@$r15+, $fr15
+	lds.l	@$r15+, $fpscr
+	lds.l	@$r15+, $fpul
+9:
+#endif
+	mov	k0,r15
 	rte
 	 nop
 
 	.balign	4
-__n_sys:	.long	NR_syscalls
-__sct:		.long	SYMBOL_NAME(sys_call_table)
-__bh_mask:	.long	SYMBOL_NAME(bh_mask)
-__bh_active:	.long	SYMBOL_NAME(bh_active)
-__dbh:		.long	SYMBOL_NAME(do_bottom_half)
 __blrb_flags:	.long	0x30000000
-__minus8192:	.long	-8192		! offset from stackbase to tsk
-__tsk_flags:	.long	flags-8192	! offset from stackbase to tsk->flags
-
+#if defined(__SH4__)
+__fpu_prepare_fd:
+	.long	SYMBOL_NAME(fpu_prepare_fd)
+__init_task_flags:
+	.long	SYMBOL_NAME(init_task_union)+4
+__PF_USEDFPU:
+	.long	PF_USEDFPU
+#endif
+1:	.long	0x000080f0	! IMASK+FD
+2:	.long	0xffff7f0f	! ~(IMASK+FD)
+3:	.long	0x00008000	! FD=1
 
 ! Exception Vector Base
 !
@@ -441,43 +529,81 @@
 	bra	handle_exception
 	 mov.l	@k2,k2
 	.balign	4
-2:	.long	SYMBOL_NAME(ret_from_syscall)
+2:	.long	SYMBOL_NAME(ret_from_exception)
 1:	.long	EXPEVT
 !
 !
 	.balign 	1024,0,1024
 tlb_miss:
 	mov.l	1f,k2
-	mov.l	3f,k3
+	mov.l	4f,k3
 	bra	handle_exception
 	 mov.l	@k2,k2
 !
 	.balign 	512,0,512
 interrupt:
 	mov.l	2f,k2
-	mov.l	4f,k3
+	mov.l	3f,k3
 	bra	handle_exception
 	 mov.l	@k2,k2
 
 	.balign	4
 1:	.long	EXPEVT
 2:	.long	INTEVT
-3:	.long	SYMBOL_NAME(ret_from_syscall)
-4:	.long	SYMBOL_NAME(ret_from_irq)
+3:	.long	SYMBOL_NAME(ret_from_irq)
+4:	.long	SYMBOL_NAME(ret_from_exception)
 
 !
 !
 handle_exception:
-	! Using k0, k1 for scratch registers (r0_bank1, and r1_bank1),
+	! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
 	! save all registers onto stack.
 	!
 	stc	ssr,k0		! from kernel space?
 	shll	k0		! Check MD bit (bit30)
 	shll	k0
-	bt/s	1f		! it's from kernel to kernel transition
+#if defined(__SH4__)
+	bf/s	8f		! it's from user to kernel transition
+	 mov	$r15, $k0	! save original stack to k0
+	/* Kernel to kernel transition */
+	mov.l	2f, $k1
+	stc	$ssr, $k0
+	tst	$k1, $k0
+	bf/s	9f		! FPU is not used
+	 mov	$r15, $k0	! save original stack to k0
+	! FPU is used, save FPU
+	! /* XXX: Need to save another bank of FPU if all FPU feature is used */
+	! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */
+	sts.l	$fpul,  @-$r15
+	sts.l	$fpscr, @-$r15
+	fmov.s	$fr15, @-$r15
+	fmov.s	$fr14, @-$r15
+	fmov.s	$fr13, @-$r15
+	fmov.s	$fr12, @-$r15
+	fmov.s	$fr11, @-$r15
+	fmov.s	$fr10, @-$r15
+	fmov.s	$fr9, @-$r15
+	fmov.s	$fr8, @-$r15
+	fmov.s	$fr7, @-$r15
+	fmov.s	$fr6, @-$r15
+	fmov.s	$fr5, @-$r15
+	fmov.s	$fr4, @-$r15
+	fmov.s	$fr3, @-$r15
+	fmov.s	$fr2, @-$r15
+	fmov.s	$fr1, @-$r15
+	fmov.s	$fr0, @-$r15
+	bra 9f
+	 mov	#0, $k1
+#else
+	bt/s	9f		! it's from kernel to kernel transition
 	 mov	r15,k0		! save original stack to k0 anyway
-	mov	kernel_sp,r15	! change to kernel stack
-1:	stc.l	spc,@-r15
+#endif
+8:	/* User space to kernel */
+	mov	kernel_sp, $r15	! change to kernel stack
+#if defined(__SH4__)
+	mov.l	2f, $k1		! let kernel release FPU
+#endif
+9:	stc.l	spc,@-r15
 	sts.l	pr,@-r15
 	!
 	lds	k3,pr		! Set the return address to pr
@@ -487,9 +613,12 @@
 	stc.l	gbr,@-r15
 	mov.l	r14,@-r15
 	!
-	mov.l	2f,k1
-	stc	sr,r14		! back to normal register bank, and
-	and	k1,r14		! ..
+	stc	sr,r14		! Back to normal register bank, and
+#if defined(__SH4__)
+	or	$k1, $r14	! may release FPU
+#endif
+	mov.l	3f,k1
+	and	k1,r14		! ...
 	ldc	r14,sr		! ...changed here.
 	!
 	mov.l	r13,@-r15
@@ -520,7 +649,8 @@
 	 mov.l	@r15,r0		! recovering r0..
 	.balign	4
 1:	.long	SYMBOL_NAME(exception_handling_table)
-2:	.long	0xdfffffff	! RB=0, BL=1
+2:	.long	0x00008000	! FD=1
+3:	.long	0xdfffffff	! RB=0, leave BL=1
 
 none:
 	rts
@@ -537,7 +667,11 @@
 	.long	tlb_protection_violation_store
 	.long	error	! address_error_load        (filled by trap_init)
 	.long	error	! address_error_store       (filled by trap_init)
+#if defined(__SH4__)
+	.long	SYMBOL_NAME(do_fpu_error)
+#else
 	.long	error	! fpu_exception
+#endif
 	.long	error
 	.long	system_call			! Unconditional Trap
 	.long	error	! reserved_instruction      (filled by trap_init)
@@ -628,8 +762,8 @@
 	.long	error
 	.long	error
 	.long	error
-	.long	error ! fpu
-	.long	error ! fpu
+	.long	SYMBOL_NAME(do_fpu_state_restore)
+	.long	SYMBOL_NAME(do_fpu_state_restore)
 #endif
 
 ENTRY(sys_call_table)
@@ -649,15 +783,15 @@
 	.long SYMBOL_NAME(sys_time)
 	.long SYMBOL_NAME(sys_mknod)
 	.long SYMBOL_NAME(sys_chmod)		/* 15 */
-	.long SYMBOL_NAME(sys_lchown)
+	.long SYMBOL_NAME(sys_lchown16)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* old break syscall holder */
 	.long SYMBOL_NAME(sys_stat)
 	.long SYMBOL_NAME(sys_lseek)
 	.long SYMBOL_NAME(sys_getpid)		/* 20 */
 	.long SYMBOL_NAME(sys_mount)
 	.long SYMBOL_NAME(sys_oldumount)
-	.long SYMBOL_NAME(sys_setuid)
-	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_setuid16)
+	.long SYMBOL_NAME(sys_getuid16)
 	.long SYMBOL_NAME(sys_stime)		/* 25 */
 	.long SYMBOL_NAME(sys_ptrace)
 	.long SYMBOL_NAME(sys_alarm)
@@ -679,13 +813,13 @@
 	.long SYMBOL_NAME(sys_times)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* old prof syscall holder */
 	.long SYMBOL_NAME(sys_brk)		/* 45 */
-	.long SYMBOL_NAME(sys_setgid)
-	.long SYMBOL_NAME(sys_getgid)
+	.long SYMBOL_NAME(sys_setgid16)
+	.long SYMBOL_NAME(sys_getgid16)
 	.long SYMBOL_NAME(sys_signal)
-	.long SYMBOL_NAME(sys_geteuid)
-	.long SYMBOL_NAME(sys_getegid)		/* 50 */
+	.long SYMBOL_NAME(sys_geteuid16)
+	.long SYMBOL_NAME(sys_getegid16)	/* 50 */
 	.long SYMBOL_NAME(sys_acct)
-	.long SYMBOL_NAME(sys_umount)					/* recycled never used phys() */
+	.long SYMBOL_NAME(sys_umount)		/* recycled never used phys() */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* old lock syscall holder */
 	.long SYMBOL_NAME(sys_ioctl)
 	.long SYMBOL_NAME(sys_fcntl)		/* 55 */
@@ -703,19 +837,19 @@
 	.long SYMBOL_NAME(sys_sigaction)
 	.long SYMBOL_NAME(sys_sgetmask)
 	.long SYMBOL_NAME(sys_ssetmask)
-	.long SYMBOL_NAME(sys_setreuid)		/* 70 */
-	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_setreuid16)	/* 70 */
+	.long SYMBOL_NAME(sys_setregid16)
 	.long SYMBOL_NAME(sys_sigsuspend)
 	.long SYMBOL_NAME(sys_sigpending)
 	.long SYMBOL_NAME(sys_sethostname)
 	.long SYMBOL_NAME(sys_setrlimit)	/* 75 */
-	.long SYMBOL_NAME(sys_getrlimit)
+	.long SYMBOL_NAME(sys_old_getrlimit)
 	.long SYMBOL_NAME(sys_getrusage)
 	.long SYMBOL_NAME(sys_gettimeofday)
 	.long SYMBOL_NAME(sys_settimeofday)
-	.long SYMBOL_NAME(sys_getgroups)	/* 80 */
-	.long SYMBOL_NAME(sys_setgroups)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* old_select */
+	.long SYMBOL_NAME(sys_getgroups16)	/* 80 */
+	.long SYMBOL_NAME(sys_setgroups16)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_oldselect */
 	.long SYMBOL_NAME(sys_symlink)
 	.long SYMBOL_NAME(sys_lstat)
 	.long SYMBOL_NAME(sys_readlink)		/* 85 */
@@ -723,18 +857,18 @@
 	.long SYMBOL_NAME(sys_swapon)
 	.long SYMBOL_NAME(sys_reboot)
 	.long SYMBOL_NAME(old_readdir)
-	.long SYMBOL_NAME(sys_mmap)		/* 90 */
+	.long SYMBOL_NAME(old_mmap)		/* 90 */
 	.long SYMBOL_NAME(sys_munmap)
 	.long SYMBOL_NAME(sys_truncate)
 	.long SYMBOL_NAME(sys_ftruncate)
 	.long SYMBOL_NAME(sys_fchmod)
-	.long SYMBOL_NAME(sys_fchown)		/* 95 */
+	.long SYMBOL_NAME(sys_fchown16)		/* 95 */
 	.long SYMBOL_NAME(sys_getpriority)
 	.long SYMBOL_NAME(sys_setpriority)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* old profil syscall holder */
 	.long SYMBOL_NAME(sys_statfs)
 	.long SYMBOL_NAME(sys_fstatfs)		/* 100 */
-	.long SYMBOL_NAME(sys_ni_syscall)		/* ioperm */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* ioperm */
 	.long SYMBOL_NAME(sys_socketcall)
 	.long SYMBOL_NAME(sys_syslog)
 	.long SYMBOL_NAME(sys_setitimer)
@@ -771,8 +905,8 @@
 	.long SYMBOL_NAME(sys_sysfs)		/* 135 */
 	.long SYMBOL_NAME(sys_personality)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* for afs_syscall */
-	.long SYMBOL_NAME(sys_setfsuid)
-	.long SYMBOL_NAME(sys_setfsgid)
+	.long SYMBOL_NAME(sys_setfsuid16)
+	.long SYMBOL_NAME(sys_setfsgid16)
 	.long SYMBOL_NAME(sys_llseek)		/* 140 */
 	.long SYMBOL_NAME(sys_getdents)
 	.long SYMBOL_NAME(sys_select)
@@ -797,14 +931,14 @@
 	.long SYMBOL_NAME(sys_sched_rr_get_interval)
 	.long SYMBOL_NAME(sys_nanosleep)
 	.long SYMBOL_NAME(sys_mremap)
-	.long SYMBOL_NAME(sys_setresuid)
-	.long SYMBOL_NAME(sys_getresuid)	/* 165 */
-	.long SYMBOL_NAME(sys_ni_syscall)		/* vm86 */
+	.long SYMBOL_NAME(sys_setresuid16)
+	.long SYMBOL_NAME(sys_getresuid16)	/* 165 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* vm86 */
 	.long SYMBOL_NAME(sys_query_module)
 	.long SYMBOL_NAME(sys_poll)
 	.long SYMBOL_NAME(sys_nfsservctl)
-	.long SYMBOL_NAME(sys_setresgid)	/* 170 */
-	.long SYMBOL_NAME(sys_getresgid)
+	.long SYMBOL_NAME(sys_setresgid16)	/* 170 */
+	.long SYMBOL_NAME(sys_getresgid16)
 	.long SYMBOL_NAME(sys_prctl)
 	.long SYMBOL_NAME(sys_rt_sigreturn)
 	.long SYMBOL_NAME(sys_rt_sigaction)
@@ -815,15 +949,42 @@
 	.long SYMBOL_NAME(sys_rt_sigsuspend)
 	.long SYMBOL_NAME(sys_pread)		/* 180 */
 	.long SYMBOL_NAME(sys_pwrite)
-	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_chown16)
 	.long SYMBOL_NAME(sys_getcwd)
 	.long SYMBOL_NAME(sys_capget)
 	.long SYMBOL_NAME(sys_capset)           /* 185 */
 	.long SYMBOL_NAME(sys_sigaltstack)
 	.long SYMBOL_NAME(sys_sendfile)
-	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
-	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* streams1 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
+	.long SYMBOL_NAME(sys_getrlimit)
+	.long SYMBOL_NAME(sys_mmap2)
+	.long SYMBOL_NAME(sys_truncate64)
+	.long SYMBOL_NAME(sys_ftruncate64)
+	.long SYMBOL_NAME(sys_stat64)		/* 195 */
+	.long SYMBOL_NAME(sys_lstat64)
+	.long SYMBOL_NAME(sys_fstat64)
+	.long SYMBOL_NAME(sys_lchown)
+	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_getgid)		/* 200 */
+	.long SYMBOL_NAME(sys_geteuid)
+	.long SYMBOL_NAME(sys_getegid)
+	.long SYMBOL_NAME(sys_setreuid)
+	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_getgroups)	/* 205 */
+	.long SYMBOL_NAME(sys_setgroups)
+	.long SYMBOL_NAME(sys_fchown)
+	.long SYMBOL_NAME(sys_setresuid)
+	.long SYMBOL_NAME(sys_getresuid)
+	.long SYMBOL_NAME(sys_setresgid)	/* 210 */
+	.long SYMBOL_NAME(sys_getresgid)
+	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_setuid)
+	.long SYMBOL_NAME(sys_setgid)
+	.long SYMBOL_NAME(sys_setfsuid)		/* 215 */
+	.long SYMBOL_NAME(sys_setfsgid)
+	.long SYMBOL_NAME(sys_pivot_root)
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
@@ -831,7 +992,7 @@
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-190
+	.rept NR_syscalls-217
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
 
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/fpu.c linux/arch/sh/kernel/fpu.c
--- v2.3.49/linux/arch/sh/kernel/fpu.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/fpu.c	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,266 @@
+/* $Id: fpu.c,v 1.27 2000/03/05 01:48:34 gniibe Exp $
+ *
+ * linux/arch/sh/kernel/fpu.c
+ *
+ * Save/restore floating point context for signal handlers.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+ *
+ * FIXME! These routines can be optimized in big endian case.
+ */
+
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+void
+save_fpu(struct task_struct *tsk)
+{
+	asm volatile("sts.l	$fpul, @-%0\n\t"
+		     "sts.l	$fpscr, @-%0\n\t"
+		     "frchg\n\t"
+		     "fmov.s	$fr15, @-%0\n\t"
+		     "fmov.s	$fr14, @-%0\n\t"
+		     "fmov.s	$fr13, @-%0\n\t"
+		     "fmov.s	$fr12, @-%0\n\t"
+		     "fmov.s	$fr11, @-%0\n\t"
+		     "fmov.s	$fr10, @-%0\n\t"
+		     "fmov.s	$fr9, @-%0\n\t"
+		     "fmov.s	$fr8, @-%0\n\t"
+		     "fmov.s	$fr7, @-%0\n\t"
+		     "fmov.s	$fr6, @-%0\n\t"
+		     "fmov.s	$fr5, @-%0\n\t"
+		     "fmov.s	$fr4, @-%0\n\t"
+		     "fmov.s	$fr3, @-%0\n\t"
+		     "fmov.s	$fr2, @-%0\n\t"
+		     "fmov.s	$fr1, @-%0\n\t"
+		     "fmov.s	$fr0, @-%0\n\t"
+		     "frchg\n\t"
+		     "fmov.s	$fr15, @-%0\n\t"
+		     "fmov.s	$fr14, @-%0\n\t"
+		     "fmov.s	$fr13, @-%0\n\t"
+		     "fmov.s	$fr12, @-%0\n\t"
+		     "fmov.s	$fr11, @-%0\n\t"
+		     "fmov.s	$fr10, @-%0\n\t"
+		     "fmov.s	$fr9, @-%0\n\t"
+		     "fmov.s	$fr8, @-%0\n\t"
+		     "fmov.s	$fr7, @-%0\n\t"
+		     "fmov.s	$fr6, @-%0\n\t"
+		     "fmov.s	$fr5, @-%0\n\t"
+		     "fmov.s	$fr4, @-%0\n\t"
+		     "fmov.s	$fr3, @-%0\n\t"
+		     "fmov.s	$fr2, @-%0\n\t"
+		     "fmov.s	$fr1, @-%0\n\t"
+		     "fmov.s	$fr0, @-%0"
+		     : /* no output */
+		     : "r" ((char *)(&tsk->thread.fpu.hard.status))
+		     : "memory");
+
+	tsk->flags &= ~PF_USEDFPU;
+	release_fpu();
+}
+
+static void
+restore_fpu(struct task_struct *tsk)
+{
+	asm volatile("fmov.s	@%0+, $fr0\n\t"
+		     "fmov.s	@%0+, $fr1\n\t"
+		     "fmov.s	@%0+, $fr2\n\t"
+		     "fmov.s	@%0+, $fr3\n\t"
+		     "fmov.s	@%0+, $fr4\n\t"
+		     "fmov.s	@%0+, $fr5\n\t"
+		     "fmov.s	@%0+, $fr6\n\t"
+		     "fmov.s	@%0+, $fr7\n\t"
+		     "fmov.s	@%0+, $fr8\n\t"
+		     "fmov.s	@%0+, $fr9\n\t"
+		     "fmov.s	@%0+, $fr10\n\t"
+		     "fmov.s	@%0+, $fr11\n\t"
+		     "fmov.s	@%0+, $fr12\n\t"
+		     "fmov.s	@%0+, $fr13\n\t"
+		     "fmov.s	@%0+, $fr14\n\t"
+		     "fmov.s	@%0+, $fr15\n\t"
+		     "frchg\n\t"
+		     "fmov.s	@%0+, $fr0\n\t"
+		     "fmov.s	@%0+, $fr1\n\t"
+		     "fmov.s	@%0+, $fr2\n\t"
+		     "fmov.s	@%0+, $fr3\n\t"
+		     "fmov.s	@%0+, $fr4\n\t"
+		     "fmov.s	@%0+, $fr5\n\t"
+		     "fmov.s	@%0+, $fr6\n\t"
+		     "fmov.s	@%0+, $fr7\n\t"
+		     "fmov.s	@%0+, $fr8\n\t"
+		     "fmov.s	@%0+, $fr9\n\t"
+		     "fmov.s	@%0+, $fr10\n\t"
+		     "fmov.s	@%0+, $fr11\n\t"
+		     "fmov.s	@%0+, $fr12\n\t"
+		     "fmov.s	@%0+, $fr13\n\t"
+		     "fmov.s	@%0+, $fr14\n\t"
+		     "fmov.s	@%0+, $fr15\n\t"
+		     "frchg\n\t"
+		     "lds.l	@%0+, $fpscr\n\t"
+		     "lds.l	@%0+, $fpul\n\t"
+		     : /* no output */
+		     : "r" (&tsk->thread.fpu)
+		     : "memory");
+}
+
+/*
+ * Load the FPU with signalling NANS.  This bit pattern we're using
+ * has the property that no matter wether considered as single or as
+ * double precission represents signaling NANS.  
+ */
+/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
+#define FPU_DEFAULT  0x00080000
+
+void fpu_init(void)
+{
+	asm volatile("lds	%0, $fpul\n\t"
+		     "lds	%1, $fpscr\n\t"
+		     "fsts	$fpul, $fr0\n\t"
+		     "fsts	$fpul, $fr1\n\t"
+		     "fsts	$fpul, $fr2\n\t"
+		     "fsts	$fpul, $fr3\n\t"
+		     "fsts	$fpul, $fr4\n\t"
+		     "fsts	$fpul, $fr5\n\t"
+		     "fsts	$fpul, $fr6\n\t"
+		     "fsts	$fpul, $fr7\n\t"
+		     "fsts	$fpul, $fr8\n\t"
+		     "fsts	$fpul, $fr9\n\t"
+		     "fsts	$fpul, $fr10\n\t"
+		     "fsts	$fpul, $fr11\n\t"
+		     "fsts	$fpul, $fr12\n\t"
+		     "fsts	$fpul, $fr13\n\t"
+		     "fsts	$fpul, $fr14\n\t"
+		     "fsts	$fpul, $fr15\n\t"
+		     "frchg\n\t"
+		     "fsts	$fpul, $fr0\n\t"
+		     "fsts	$fpul, $fr1\n\t"
+		     "fsts	$fpul, $fr2\n\t"
+		     "fsts	$fpul, $fr3\n\t"
+		     "fsts	$fpul, $fr4\n\t"
+		     "fsts	$fpul, $fr5\n\t"
+		     "fsts	$fpul, $fr6\n\t"
+		     "fsts	$fpul, $fr7\n\t"
+		     "fsts	$fpul, $fr8\n\t"
+		     "fsts	$fpul, $fr9\n\t"
+		     "fsts	$fpul, $fr10\n\t"
+		     "fsts	$fpul, $fr11\n\t"
+		     "fsts	$fpul, $fr12\n\t"
+		     "fsts	$fpul, $fr13\n\t"
+		     "fsts	$fpul, $fr14\n\t"
+		     "fsts	$fpul, $fr15\n\t"
+		     "frchg"
+		     : /* no output */
+		     : "r" (0), "r" (FPU_DEFAULT));
+}
+
+asmlinkage void
+do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7,
+	     struct pt_regs regs)
+{
+	struct task_struct *tsk = current;
+
+	regs.syscall_nr = -1;
+	regs.pc += 2;
+
+	grab_fpu();
+	save_fpu(tsk);
+	tsk->thread.trap_no = 11;
+	tsk->thread.error_code = 0;
+	force_sig(SIGFPE, tsk);
+}
+
+asmlinkage void
+do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
+		     unsigned long r7, struct pt_regs regs)
+{
+	struct task_struct *tsk = current;
+
+	regs.syscall_nr = -1;
+
+	if (!user_mode(&regs)) {
+		if (tsk != &init_task) {
+			unlazy_fpu(tsk);
+		}
+		tsk = &init_task;
+		if (tsk->flags & PF_USEDFPU)
+			BUG();
+	}
+
+	grab_fpu();
+	if (tsk->used_math) {
+		/* Using the FPU again.  */
+		restore_fpu(tsk);
+	} else	{
+		/* First time FPU user.  */
+		fpu_init();
+		tsk->used_math = 1;
+	}
+	tsk->flags |= PF_USEDFPU;
+	release_fpu();
+}
+
+/*
+ * Change current FD flag to set FD flag back to exception
+ */
+asmlinkage void
+fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6,
+	       unsigned long r7, struct pt_regs regs)
+{
+	__cli();
+	if (!user_mode(&regs)) {
+		if (init_task.flags & PF_USEDFPU)
+			grab_fpu();
+		else {
+			if (!(sr & SR_FD)) {
+				release_fpu();
+				BUG();
+			}
+		}
+		return;
+	}
+
+	if (sr & SR_FD) { /* Kernel doesn't grab FPU */
+		if (current->flags & PF_USEDFPU)
+			grab_fpu();
+		else {
+			if (init_task.flags & PF_USEDFPU) {
+				init_task.flags &= ~PF_USEDFPU;
+				BUG();
+			}
+		}
+	} else {
+		if (init_task.flags & PF_USEDFPU)
+			save_fpu(&init_task);
+		else {
+			release_fpu();
+			BUG();
+		}
+	}
+}
+
+/* Short cut for the FPU exception */
+asmlinkage void
+enable_fpu_in_danger(void)
+{
+	struct task_struct *tsk = current;
+
+	if (tsk != &init_task)
+		unlazy_fpu(tsk);
+
+	tsk = &init_task;
+	if (tsk->used_math) {
+		/* Using the FPU again.  */
+		restore_fpu(tsk);
+	} else	{
+		/* First time FPU user.  */
+		fpu_init();
+		tsk->used_math = 1;
+	}
+	tsk->flags |= PF_USEDFPU;
+}
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S
--- v2.3.49/linux/arch/sh/kernel/head.S	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/kernel/head.S	Sun Mar  5 09:33:55 2000
@@ -1,8 +1,8 @@
-/* $Id: head.S,v 1.7 1999/10/27 09:41:42 gniibe Exp gniibe $
+/* $Id: head.S,v 1.16 2000/03/02 00:01:15 gniibe Exp $
  *
  *  arch/sh/kernel/head.S
  *
- *  Copyright (C) 1999  Niibe Yutaka & Kaz Kojima
+ *  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -34,49 +34,37 @@
  *   Cache may or may not be initialized.
  *   Hardware (including on-chip modules) may or may not be initialized. 
  *
- *   The register R4&R5 holds the address of the parameter block, which has
- *   command-line data, etc.
- *
  */
 ENTRY(_stext)
-#if defined(__SH4__)
-	!			Initialize FPSCR	
-	/* GCC (as of 2.95.1) assumes FPU with double precision mode. */
-	mov.l	7f,r0
-	lds	r0,fpscr
-#endif
 	!			Initialize Status Register
-	mov.l	1f,r0		! MD=1, RB=0, BL=1
-	ldc	r0,sr
+	mov.l	1f, $r0		! MD=1, RB=0, BL=1
+	ldc	$r0, $sr
 	!
-	mov.l	2f,r0
-	mov	r0,r15		! Set initial r15 (stack pointer)
-	ldc	r0,r4_bank	!   and stack base
+	mov.l	2f, $r0
+	mov	$r0, $r15	! Set initial r15 (stack pointer)
+	ldc	$r0, $r4_bank	!   and stack base
 	!
 	!			Enable cache
-	mov.l	6f,r0
-	jsr	@r0
+	mov.l	6f, $r0
+	jsr	@$r0
 	 nop
 	!			Clear BSS area
-	mov.l	3f,r1
-	add	#4,r1
-	mov.l	4f,r2
-	mov	#0,r0
-9:	cmp/hs	r2,r1
+	mov.l	3f, $r1
+	add	#4, $r1
+	mov.l	4f, $r2
+	mov	#0, $r0
+9:	cmp/hs	$r2, $r1
 	bf/s	9b		! while (r1 < r2)
-	 mov.l	r0,@-r2
+	 mov.l	$r0,@-$r2
 	!			Start kernel
-	mov.l	5f,r0
-	jmp	@r0
+	mov.l	5f, $r0
+	jmp	@$r0
 	 nop
 
 	.balign 4
-1:	.long	0x50000000		! MD=1, RB=0, BL=1
+1:	.long	0x50000000		! MD=1, RB=0, BL=1, FD=0
 2:	.long	SYMBOL_NAME(stack)
 3:	.long	SYMBOL_NAME(__bss_start)
 4:	.long	SYMBOL_NAME(_end)
 5:	.long	SYMBOL_NAME(start_kernel)
 6:	.long	SYMBOL_NAME(cache_init)
-#if defined(__SH4__)
-7:	.long   0x00080000
-#endif
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c
--- v2.3.49/linux/arch/sh/kernel/irq.c	Fri Oct 22 13:21:46 1999
+++ linux/arch/sh/kernel/irq.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.4 1999/10/11 13:12:14 gniibe Exp $
+/* $Id: irq.c,v 1.11 2000/02/29 11:03:40 gniibe Exp $
  *
  * linux/arch/sh/kernel/irq.c
  *
@@ -31,7 +31,7 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/smp.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <linux/irq.h>
@@ -49,7 +49,8 @@
 /*
  * Controller mappings for all interrupt sources:
  */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+				{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
 
 /*
  * Special irq handlers.
@@ -112,9 +113,8 @@
 		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
 		p += sprintf(p, "  %s", action->name);
 
-		for (action=action->next; action; action = action->next) {
+		for (action=action->next; action; action = action->next)
 			p += sprintf(p, ", %s", action->name);
-		}
 		*p++ = '\n';
 	}
 	return p - buf;
@@ -248,7 +248,7 @@
 	kstat.irqs[cpu][irq]++;
 	desc = irq_desc + irq;
 	spin_lock(&irq_controller_lock);
-	irq_desc[irq].handler->ack(irq);
+	desc->handler->ack(irq);
 	/*
 	   REPLAY is when Linux resends an IRQ that was dropped earlier
 	   WAITING is used by probe to mark irqs that are being tested
@@ -298,21 +298,15 @@
 		spin_unlock(&irq_controller_lock);
 	}
 	desc->status &= ~IRQ_INPROGRESS;
-	if (!(desc->status & IRQ_DISABLED)){
-		irq_desc[irq].handler->end(irq);
-	}
+	if (!(desc->status & IRQ_DISABLED))
+		desc->handler->end(irq);
 	spin_unlock(&irq_controller_lock);
 
-	/*
-	 * This should be conditional: we should really get
-	 * a return code from the irq handler to tell us
-	 * whether the handler wants us to do software bottom
-	 * half handling or not..
-	 */
-	if (1) {
-		if (bh_active & bh_mask)
-			do_bottom_half();
-	}
+#if 1
+	__sti();
+#endif
+	if (softirq_state[cpu].active&softirq_state[cpu].mask)
+		do_softirq();
 	return 1;
 }
 
@@ -347,7 +341,7 @@
 		kfree(action);
 	return retval;
 }
-		
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction **p;
@@ -373,10 +367,6 @@
 				irq_desc[irq].handler->shutdown(irq);
 			}
 			spin_unlock_irqrestore(&irq_controller_lock,flags);
-
-			/* Wait to make sure it's not being used on another CPU */
-			while (irq_desc[irq].status & IRQ_INPROGRESS)
-				barrier();
 			kfree(action);
 			return;
 		}
@@ -398,6 +388,7 @@
 {
 	unsigned int i;
 	unsigned long delay;
+	unsigned long val;
 
 	/*
 	 * first, enable any unassigned irqs
@@ -421,6 +412,7 @@
 	/*
 	 * Now filter out any obviously spurious interrupts
 	 */
+	val = 0;
 	spin_lock_irq(&irq_controller_lock);
 	for (i=0; i<NR_IRQS; i++) {
 		unsigned int status = irq_desc[i].status;
@@ -433,18 +425,18 @@
 			irq_desc[i].status = status & ~IRQ_AUTODETECT;
 			irq_desc[i].handler->shutdown(i);
 		}
+
+		if (i < 32)
+			val |= 1 << i;
 	}
 	spin_unlock_irq(&irq_controller_lock);
 
-	return 0x12345678;
+	return val;
 }
 
-int probe_irq_off(unsigned long unused)
+int probe_irq_off(unsigned long val)
 {
 	int i, irq_found, nr_irqs;
-
-	if (unused != 0x12345678)
-		printk("Bad IRQ probe from %lx\n", (&unused)[-1]);
 
 	nr_irqs = 0;
 	irq_found = 0;
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/irq_imask.c linux/arch/sh/kernel/irq_imask.c
--- v2.3.49/linux/arch/sh/kernel/irq_imask.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/irq_imask.c	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,106 @@
+/* $Id: irq_imask.c,v 1.2 2000/02/11 04:57:40 gniibe Exp $
+ *
+ * linux/arch/sh/kernel/irq_imask.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ * Simple interrupt handling using IMASK of SR register.
+ *
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/irq.h>
+
+/* Bitmap of IRQ masked */
+static unsigned long imask_mask = 0x7fff;
+static int interrupt_priority = 0;
+
+static void enable_imask_irq(unsigned int irq);
+static void disable_imask_irq(unsigned int irq);
+static void shutdown_imask_irq(unsigned int irq);
+static void mask_and_ack_imask(unsigned int);
+static void end_imask_irq(unsigned int irq);
+
+#define IMASK_PRIORITY	15
+
+static unsigned int startup_imask_irq(unsigned int irq)
+{ 
+	enable_imask_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type imask_irq_type = {
+	"Interrupt using IMASK of SR register",
+	startup_imask_irq,
+	shutdown_imask_irq,
+	enable_imask_irq,
+	disable_imask_irq,
+	mask_and_ack_imask,
+	end_imask_irq
+};
+
+void disable_imask_irq(unsigned int irq)
+{
+	unsigned long __dummy;
+
+	clear_bit(irq, &imask_mask);
+	if (interrupt_priority < IMASK_PRIORITY - irq)
+		interrupt_priority = IMASK_PRIORITY - irq;
+
+	asm volatile("stc	sr,%0\n\t"
+		     "and	%1,%0\n\t"
+		     "or	%2,%0\n\t"
+		     "ldc	%0,sr"
+		     : "=&r" (__dummy)
+		     : "r" (0xffffff0f), "r" (interrupt_priority << 4));
+}
+
+static void enable_imask_irq(unsigned int irq)
+{
+	unsigned long __dummy;
+
+	set_bit(irq, &imask_mask);
+	interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
+
+	asm volatile("stc	sr,%0\n\t"
+		     "and	%1,%0\n\t"
+		     "or	%2,%0\n\t"
+		     "ldc	%0,sr"
+		     : "=&r" (__dummy)
+		     : "r" (0xffffff0f), "r" (interrupt_priority << 4));
+}
+
+static void mask_and_ack_imask(unsigned int irq)
+{
+	disable_imask_irq(irq);
+}
+
+static void end_imask_irq(unsigned int irq)
+{
+	enable_imask_irq(irq);
+}
+
+static void shutdown_imask_irq(unsigned int irq)
+{
+	disable_imask_irq(irq);
+}
+
+void make_imask_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	irq_desc[irq].handler = &imask_irq_type;
+	enable_irq(irq);
+}
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c
--- v2.3.49/linux/arch/sh/kernel/irq_onchip.c	Thu Nov 18 20:25:37 1999
+++ linux/arch/sh/kernel/irq_onchip.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: irq_onchip.c,v 1.5 1999/10/28 02:18:33 gniibe Exp $
+/* $Id: irq_onchip.c,v 1.7 2000-01-09 15:55:55+09 gniibe Exp $
  *
  * linux/arch/sh/kernel/irq_onchip.c
  *
@@ -143,7 +143,18 @@
  */
 
 #define INTC_IRR0	0xa4000004UL
-#define INTC_IPRC	0xa4000016UL
+#define INTC_IRR1	0xa4000006UL
+#define INTC_IRR2	0xa4000008UL
+
+#define INTC_ICR0  	0xfffffee0
+#define INTC_ICR1  	0xa4000010
+#define INTC_ICR2  	0xa4000012
+#define INTC_INTER 	0xa4000014
+#define INTC_IPRA  	0xfffffee2
+#define INTC_IPRB  	0xfffffee4
+#define INTC_IPRC  	0xa4000016
+#define INTC_IPRD  	0xa4000018
+#define INTC_IPRE  	0xa400001a
 
 #define IRQ0_IRQ	32
 #define IRQ1_IRQ	33
@@ -248,6 +259,26 @@
 	}
 
 #ifdef CONFIG_CPU_SUBTYPE_SH7709
+
+	/*
+	 * Initialize the Interrupt Controller (INTC)
+	 * registers to their power on values
+	 */ 
+
+	ctrl_outb(0, INTC_IRR0);
+	ctrl_outb(0, INTC_IRR1);
+	ctrl_outb(0, INTC_IRR2);
+
+	ctrl_outw(0, INTC_ICR0);
+	ctrl_outw(0, INTC_ICR1);
+	ctrl_outw(0, INTC_ICR2);
+	ctrl_outw(0, INTC_INTER);
+	ctrl_outw(0, INTC_IPRA);
+	ctrl_outw(0, INTC_IPRB);
+	ctrl_outw(0, INTC_IPRC);
+	ctrl_outw(0, INTC_IPRD);
+	ctrl_outw(0, INTC_IPRE);
+
 	for (i = IRQ0_IRQ; i < NR_IRQS; i++) {
 		irq_desc[i].handler = &onChip2_irq_type;
 	}
@@ -263,8 +294,5 @@
 	set_ipr_data(IRQ3_IRQ, IRQ3_IRP_OFFSET, IRQ3_PRIORITY);
 	set_ipr_data(IRQ4_IRQ, IRQ4_IRP_OFFSET, IRQ4_PRIORITY);
 	set_ipr_data(IRQ5_IRQ, IRQ5_IRP_OFFSET, IRQ5_PRIORITY);
-
-	ctrl_inb(INTC_IRR0);
-	ctrl_outb(0, INTC_IRR0);
 #endif /* CONFIG_CPU_SUBTYPE_SH7709 */
 }
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/pci-sh.c linux/arch/sh/kernel/pci-sh.c
--- v2.3.49/linux/arch/sh/kernel/pci-sh.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci-sh.c	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,12 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+			     unsigned long start, unsigned long size)
+{
+	return start;
+}
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.3.49/linux/arch/sh/kernel/process.c	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/kernel/process.c	Sun Mar  5 09:33:55 2000
@@ -1,10 +1,10 @@
-/* $Id: process.c,v 1.8 1999/10/31 13:19:16 gniibe Exp $
+/* $Id: process.c,v 1.28 2000/03/05 02:16:15 gniibe Exp $
  *
  *  linux/arch/sh/kernel/process.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *
- *  SuperH version:  Copyright (C) 1999  Niibe Yutaka & Kaz Kojima
+ *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  */
 
 /*
@@ -42,10 +42,6 @@
 
 #include <linux/irq.h>
 
-#if defined(__SH4__)
-struct task_struct *last_task_used_math = NULL;
-#endif
-
 static int hlt_counter=0;
 
 #define HARD_IDLE_TIMEOUT (HZ / 3)
@@ -140,25 +136,25 @@
  */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
-	register unsigned long __sc0 __asm__ ("r0") = __NR_clone;
-	register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM;
-	register unsigned long __sc5 __asm__ ("r5") = 0;
-	register unsigned long __sc8 __asm__ ("r8") = (long) arg;
-	register unsigned long __sc9 __asm__ ("r9") = (long) fn;
-	__asm__ __volatile__(
-		"trapa	#0\n\t" 	/* Linux/SH system call */
-		"tst	#0xff,r0\n\t"	/* child or parent? */
+	register unsigned long __sc0 __asm__ ("$r0") = __NR_clone;
+	register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM;
+	register unsigned long __sc5 __asm__ ("$r5") = 0;
+	register unsigned long __sc8 __asm__ ("$r8") = (long) arg;
+	register unsigned long __sc9 __asm__ ("$r9") = (long) fn;
+
+	__asm__("trapa	#0\n\t" 	/* Linux/SH system call */
+		"tst	#0xff, $r0\n\t"	/* child or parent? */
 		"bf	1f\n\t"		/* parent - jump */
-		"jsr	@r9\n\t"	/* call fn */
-		" mov	r8,r4\n\t"	/* push argument */
-		"mov	r0,r4\n\t"	/* return value to arg of exit */
-		"mov	%2,r0\n\t"	/* exit */
+		"jsr	@$r9\n\t"	/* call fn */
+		" mov	$r8, $r4\n\t"	/* push argument */
+		"mov	$r0, $r4\n\t"	/* return value to arg of exit */
+		"mov	%2, $r0\n\t"	/* exit */
 		"trapa	#0\n"
 		"1:"
-		:"=z" (__sc0)
-		:"0" (__sc0), "i" (__NR_exit),
-		 "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9)
-		:"memory");
+		: "=z" (__sc0)
+		: "0" (__sc0), "i" (__NR_exit),
+		  "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9)
+		: "memory");
 	return __sc0;
 }
 
@@ -167,18 +163,7 @@
  */
 void exit_thread(void)
 {
-#if defined(__sh3__)
-	/* nothing to do ... */
-#elif defined(__SH4__)
-#if 0 /* for the time being... */
-	/* Forget lazy fpu state */
-	if (last_task_used_math == current) {
-		set_status_register (SR_FD, 0);
-		write_system_register (fpscr, FPSCR_PR);
-		last_task_used_math = NULL;
-	}
-#endif
-#endif
+	/* Nothing to do. */
 }
 
 void flush_thread(void)
@@ -187,14 +172,11 @@
 	/* do nothing */
 	/* Possibly, set clear debug registers */
 #elif defined(__SH4__)
-#if 0 /* for the time being... */
-	/* Forget lazy fpu state */
-	if (last_task_used_math == current) {
-		set_status_register (SR_FD, 0);
-		write_system_register (fpscr, FPSCR_PR);
-		last_task_used_math = NULL;
-	}
-#endif
+	struct task_struct *tsk = current;
+
+	/* Forget lazy FPU state */
+	clear_fpu(tsk);
+	tsk->used_math = 0;
 #endif
 }
 
@@ -204,18 +186,22 @@
 }
 
 /* Fill in the fpu structure for a core dump.. */
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 {
 #if defined(__SH4__)
-#if 0 /* for the time being... */
-	    /* We store the FPU info in the task->thread area.  */
-	    if (! (regs->sr & SR_FD)) {
-		    memcpy (r, &current->thread.fpu, sizeof (*r));
-		    return 1;
-	    }
-#endif
-#endif
+	int fpvalid;
+	struct task_struct *tsk = current;
+
+	fpvalid = tsk->used_math;
+	if (fpvalid) {
+		unlazy_fpu(tsk);
+		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+	}
+
+	return fpvalid;
+#else
 	return 0; /* Task didn't use the fpu at all. */
+#endif
 }
 
 asmlinkage void ret_from_fork(void);
@@ -224,21 +210,17 @@
 		struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs;
+	struct task_struct *tsk = current;
 
 	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
-	*childregs = *regs;
+	struct_cpy(childregs, regs);
 
 #if defined(__SH4__)
-#if 0 /* for the time being... */
-	if (last_task_used_math == current) {
-		set_status_register (SR_FD, 0);
-		sh4_save_fp (p);
+	if (tsk != &init_task) {
+		unlazy_fpu(tsk);
+		struct_cpy(&p->thread.fpu, &current->thread.fpu);
+		p->used_math = tsk->used_math;
 	}
-	/* New tasks loose permission to use the fpu. This accelerates context
-	   switching for most programs since they don't use the fpu.  */
-	p->thread.sr = (read_control_register (sr) &~ SR_MD) | SR_FD;
-	childregs->sr |= SR_FD;
-#endif
 #endif
 	if (user_mode(regs)) {
 		childregs->sp = usp;
@@ -246,6 +228,7 @@
 		childregs->sp = (unsigned long)p+2*PAGE_SIZE;
 	}
 	childregs->regs[0] = 0; /* Set return value for child */
+	childregs->sr |= SR_FD; /* Invalidate FPU flag */
 
 	p->thread.sp = (unsigned long) childregs;
 	p->thread.pc = (unsigned long) ret_from_fork;
@@ -258,7 +241,6 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-/* changed the size calculations - should hopefully work better. lbt */
 	dump->magic = CMAGIC;
 	dump->start_code = current->mm->start_code;
 	dump->start_data  = current->mm->start_data;
@@ -271,11 +253,7 @@
 
 	dump->regs = *regs;
 
-#if 0 /* defined(__SH4__) */
-	/* FPU */
-	memcpy (&dump->regs[EF_SIZE/4], &current->thread.fpu,
-		sizeof (current->thread.fpu));
-#endif
+	dump->u_fpvalid = dump_fpu(regs, &dump->fpu);
 }
 
 /*
@@ -284,11 +262,15 @@
  */
 void __switch_to(struct task_struct *prev, struct task_struct *next)
 {
+#if defined(__SH4__)
+	if (prev != &init_task)
+		unlazy_fpu(prev);
+#endif
 	/*
 	 * Restore the kernel stack onto kernel mode register
 	 *   	k4 (r4_bank1)
 	 */
-	asm volatile("ldc	%0,r4_bank"
+	asm volatile("ldc	%0, $r4_bank"
 		     : /* no output */
 		     :"r" ((unsigned long)next+8192));
 }
@@ -341,6 +323,7 @@
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
+
 	error = do_execve(filename, uargv, uenvp, &regs);
 	if (error == 0)
 		current->flags &= ~PF_DTRACE;
@@ -348,4 +331,42 @@
 out:
 	unlock_kernel();
 	return error;
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched	((unsigned long) scheduling_functions_start_here)
+#define last_sched	((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long schedule_frame;
+	unsigned long pc;
+
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	/*
+	 * The same comment as on the Alpha applies here, too ...
+	 */
+	pc = thread_saved_pc(&p->thread);
+	if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
+		schedule_frame = ((unsigned long *)(long)p->thread.sp)[1];
+		return (unsigned long)((unsigned long *)schedule_frame)[1];
+	}
+	return pc;
+}
+
+asmlinkage void print_syscall(int x)
+{
+	unsigned long flags, sr;
+	asm("stc	$sr, %0": "=r" (sr));
+	save_and_cli(flags);
+	printk("%c: %c %c, %c: SYSCALL\n", (x&63)+32,
+	       (current->flags&PF_USEDFPU)?'C':' ',
+	       (init_task.flags&PF_USEDFPU)?'K':' ', (sr&SR_FD)?' ':'F');
+	restore_flags(flags);
 }
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/semaphore.c linux/arch/sh/kernel/semaphore.c
--- v2.3.49/linux/arch/sh/kernel/semaphore.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/semaphore.c	Sun Mar  5 09:33:55 2000
@@ -8,6 +8,8 @@
  */
 
 #include <linux/sched.h>
+#include <linux/wait.h>
+#include <asm/semaphore.h>
 #include <asm/semaphore-helper.h>
 
 /*
@@ -130,4 +132,163 @@
 int __down_trylock(struct semaphore * sem)
 {
 	return waking_non_zero_trylock(sem);
+}
+
+/* Called when someone has done an up that transitioned from
+ * negative to non-negative, meaning that the lock has been
+ * granted to whomever owned the bias.
+ */
+struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
+{
+	if (xchg(&sem->read_bias_granted, 1))
+		BUG();
+	wake_up(&sem->wait);
+	return sem;
+}
+
+struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
+{
+	if (xchg(&sem->write_bias_granted, 1))
+		BUG();
+	wake_up(&sem->write_bias_wait);
+	return sem;
+}
+
+struct rw_semaphore * __rwsem_wake(struct rw_semaphore *sem)
+{
+	if (atomic_read(&sem->count) == 0)
+		return rwsem_wake_writer(sem);
+	else
+		return rwsem_wake_readers(sem);
+}
+
+struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
+
+	for (;;) {
+		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
+			break;
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+		if (!sem->read_bias_granted)
+			schedule();
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	add_wait_queue_exclusive(&sem->write_bias_wait, &wait);	/* put ourselves at the end of the list */
+
+	for (;;) {
+		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
+			break;
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+		if (!sem->write_bias_granted)
+			schedule();
+	}
+
+	remove_wait_queue(&sem->write_bias_wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	/* if the lock is currently unbiased, awaken the sleepers
+	 * FIXME: this wakes up the readers early in a bit of a
+	 * stampede -> bad!
+	 */
+	if (atomic_read(&sem->count) >= 0)
+		wake_up(&sem->wait);
+
+	return sem;
+}
+
+/* Wait for the lock to become unbiased.  Readers
+ * are non-exclusive. =)
+ */
+struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	__up_read(sem);	/* this takes care of granting the lock */
+
+	add_wait_queue(&sem->wait, &wait);
+
+	while (atomic_read(&sem->count) < 0) {
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+		if (atomic_read(&sem->count) >= 0)
+			break;
+		schedule();
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+/* Wait for the lock to become unbiased. Since we're
+ * a writer, we'll make ourselves exclusive.
+ */
+struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	__up_write(sem);	/* this takes care of granting the lock */
+
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	while (atomic_read(&sem->count) < 0) {
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+		if (atomic_read(&sem->count) >= 0)
+			break;	/* we must attempt to aquire or bias the lock */
+		schedule();
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry)
+{
+	if (carry) {
+		int saved, new;
+
+		do {
+			down_read_failed(sem);
+			saved = atomic_read(&sem->count);
+			if ((new = atomic_dec_return(&sem->count)) >= 0)
+				return sem;
+		} while (!(new < 0 && saved >=0));
+	}
+
+	return down_read_failed_biased(sem);
+}
+
+struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry)
+{
+	if (carry) {
+		int saved, new;
+
+		do {
+			down_write_failed(sem);
+			saved = atomic_read(&sem->count);
+			if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count) ) == 0)
+				return sem;
+		} while (!(new < 0 && saved >=0));
+	}
+
+	return down_write_failed_biased(sem);
 }
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- v2.3.49/linux/arch/sh/kernel/setup.c	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/kernel/setup.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.7 1999/10/23 01:34:50 gniibe Exp gniibe $
+/* $Id: setup.c,v 1.20 2000/03/05 02:44:41 gniibe Exp $
  *
  *  linux/arch/sh/kernel/setup.c
  *
@@ -51,6 +51,7 @@
 extern int rd_image_start;	/* starting block # of image */
 #endif
 
+extern void fpu_init(void);
 extern int root_mountflags;
 extern int _text, _etext, _edata, _end;
 
@@ -196,82 +197,82 @@
 #define PFN_PHYS(x)	((x) << PAGE_SHIFT)
 
 	/*
-	 * partially used pages are not usable - thus
-	 * we are rounding upwards:
-	 */
-	start_pfn = PFN_UP(__pa(&_end)-__MEMORY_START);
-
-	/*
 	 * Find the highest page frame number we have available
 	 */
-	max_pfn = PFN_DOWN(__pa(memory_end)-__MEMORY_START);
+	max_pfn = PFN_DOWN(__pa(memory_end));
 
 	/*
 	 * Determine low and high memory ranges:
 	 */
 	max_low_pfn = max_pfn;
 
+ 	/*
+	 * Partially used pages are not usable - thus
+	 * we are rounding upwards:
+ 	 */
+	start_pfn = PFN_UP(__pa(&_end));
 	/*
-	 * Initialize the boot-time allocator (with low memory only):
-	 */
-	bootmap_size = init_bootmem(start_pfn, max_low_pfn, __MEMORY_START);
-
-	/*
-	 * FIXME: what about high memory?
+	 * Find a proper area for the bootmem bitmap. After this
+	 * bootstrap step all allocations (until the page allocator
+	 * is intact) must be done via bootmem_alloc().
 	 */
-	ram_resources[1].end = PFN_PHYS(max_low_pfn) + __MEMORY_START;
+	bootmap_size = init_bootmem_node(0, start_pfn,
+					 __MEMORY_START>>PAGE_SHIFT, 
+					 max_low_pfn);
 
 	/*
 	 * Register fully available low RAM pages with the bootmem allocator.
 	 */
 	{
-		unsigned long curr_pfn, last_pfn, size;
+		unsigned long curr_pfn, last_pfn, pages;
 
 		/*
 		 * We are rounding up the start address of usable memory:
 		 */
-		curr_pfn = PFN_UP(0);
+		curr_pfn = PFN_UP(__MEMORY_START);
 		/*
 		 * ... and at the end of the usable range downwards:
 		 */
-		last_pfn = PFN_DOWN(memory_end-__MEMORY_START);
+		last_pfn = PFN_DOWN(__pa(memory_end));
 
 		if (last_pfn > max_low_pfn)
 			last_pfn = max_low_pfn;
 
-		size = last_pfn - curr_pfn;
-		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
+		pages = last_pfn - curr_pfn;
+		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
 	}
+
 	/*
 	 * Reserve the kernel text and
-	 * Reserve the bootmem bitmap itself as well. We do this in two
-	 * steps (first step was init_bootmem()) because this catches
-	 * the (very unlikely) case of us accidentally initializing the
-	 * bootmem allocator with an invalid RAM area.
+	 * Reserve the bootmem bitmap.We do this in two steps (first step
+	 * was init_bootmem()), because this catches the (definitely buggy)
+	 * case of us accidentally initializing the bootmem allocator with
+	 * an invalid RAM area.
 	 */
-	reserve_bootmem(PAGE_SIZE, PFN_PHYS(start_pfn) + bootmap_size);
+	reserve_bootmem(__MEMORY_START+PAGE_SIZE, (PFN_PHYS(start_pfn) + 
+			bootmap_size + PAGE_SIZE-1) - __MEMORY_START);
 
 	/*
 	 * reserve physical page 0 - it's a special BIOS page on many boxes,
 	 * enabling clean reboots, SMP operation, laptop functions.
 	 */
-	reserve_bootmem(0, PAGE_SIZE);
+	reserve_bootmem(__MEMORY_START, PAGE_SIZE);
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	if (LOADER_TYPE) {
+	if (LOADER_TYPE && INITRD_START) {
 		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
-			reserve_bootmem(INITRD_START, INITRD_SIZE);
-			initrd_start =
-				INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0;
-			initrd_end = initrd_start+INITRD_SIZE;
+			reserve_bootmem(INITRD_START+__MEMORY_START, INITRD_SIZE);
+ 			initrd_start =
+ 				INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0;
+			initrd_end = initrd_start + INITRD_SIZE;
 		} else {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-			    INITRD_START + INITRD_SIZE,
-			    max_low_pfn << PAGE_SHIFT);
-			initrd_start = 0;
-		}
-	}
+ 			printk("initrd extends beyond end of memory "
+ 			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+				    INITRD_START + INITRD_SIZE,
+				    max_low_pfn << PAGE_SHIFT);
+ 			initrd_start = 0;
+ 		}
+ 	}
 #endif
 
 #if 0
@@ -298,6 +299,14 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
+
+#if defined(__SH4__)
+	init_task.used_math = 1;
+	init_task.flags |= PF_USEDFPU;
+	grab_fpu();
+	fpu_init();
+#endif
+	paging_init();
 }
 
 /*
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c
--- v2.3.49/linux/arch/sh/kernel/signal.c	Tue Nov 23 22:42:20 1999
+++ linux/arch/sh/kernel/signal.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.10 1999/09/27 23:25:44 gniibe Exp $
+/* $Id: signal.c,v 1.16 2000/01/29 11:31:31 gniibe Exp gniibe $
  *
  *  linux/arch/sh/kernel/signal.c
  *
@@ -54,7 +54,7 @@
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&regs,&saveset))
+		if (do_signal(&regs, &saveset))
 			return -EINTR;
 	}
 }
@@ -73,7 +73,6 @@
 	if (copy_from_user(&newset, unewset, sizeof(newset)))
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
-
 	spin_lock_irq(&current->sigmask_lock);
 	saveset = current->blocked;
 	current->blocked = newset;
@@ -188,6 +187,7 @@
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
+
 	if (__get_user(set.sig[0], &frame->sc.oldmask)
 	    || (_NSIG_WORDS > 1
 		&& __copy_from_user(&set.sig[1], &frame->extramask,
@@ -195,6 +195,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
+
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
@@ -220,6 +221,7 @@
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
+
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto badframe;
 
@@ -228,7 +230,7 @@
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
-	
+
 	if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &r0))
 		goto badframe;
 
@@ -317,7 +319,7 @@
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		regs->pr = (unsigned long) ka->sa.sa_restorer;
 	} else {
-		/* This is ; mov  #__NR_sigreturn,r0 ; trapa #0 */
+		/* This is : mov  #__NR_sigreturn,r0 ; trapa #0 */
 #ifdef __LITTLE_ENDIAN__
 		unsigned long code = 0xc300e000 | (__NR_sigreturn);
 #else
@@ -390,11 +392,11 @@
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		regs->pr = (unsigned long) ka->sa.sa_restorer;
 	} else {
-		/* This is ; mov  #__NR_sigreturn,r0 ; trapa #0 */
+		/* This is : mov  #__NR_rt_sigreturn,r0 ; trapa #0 */
 #ifdef __LITTLE_ENDIAN__
-		unsigned long code = 0xc300e000 | (__NR_sigreturn);
+		unsigned long code = 0xc300e000 | (__NR_rt_sigreturn);
 #else
-		unsigned long code = 0xe000c300 | (__NR_sigreturn << 16);
+		unsigned long code = 0xe000c300 | (__NR_rt_sigreturn << 16);
 #endif
 
 		regs->pr = (unsigned long) frame->retcode;
@@ -485,6 +487,15 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 
+	/*
+	 * We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 1;
+
 	if (!oldset)
 		oldset = &current->blocked;
 
@@ -580,6 +591,7 @@
 				/* NOTREACHED */
 			}
 		}
+
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c
--- v2.3.49/linux/arch/sh/kernel/sys_sh.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sh/kernel/sys_sh.c	Sun Mar  5 09:33:55 2000
@@ -28,7 +28,9 @@
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way Unix traditionally does this, though.
  */
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
+	unsigned long r6, unsigned long r7,
+	struct pt_regs regs)
 {
 	int fd[2];
 	int error;
@@ -37,46 +39,62 @@
 	error = do_pipe(fd);
 	unlock_kernel();
 	if (!error) {
-		if (copy_to_user(fildes, fd, 2*sizeof(int)))
-			error = -EFAULT;
+		regs.regs[1] = fd[1];
+		return fd[0];
 	}
 	return error;
 }
 
-asmlinkage unsigned long
-sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, 
-	 unsigned long flags, int fd, unsigned long off)
+static inline long
+do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 
+	 unsigned long flags, int fd, unsigned long pgoff)
 {
-	int error = -EFAULT;
+	int error = -EBADF;
 	struct file *file = NULL;
 
-	down(&current->mm->mmap_sem);
-	lock_kernel();
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
-		error = -EBADF;
 		file = fget(fd);
 		if (!file)
 			goto out;
 	}
-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	error = do_mmap(file, addr, len, prot, flags, off);
-	if (file)
-		fput(file);
-out:
+	down(&current->mm->mmap_sem);
+	lock_kernel();
+
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	unlock_kernel();
 	up(&current->mm->mmap_sem);
 
+	if (file)
+		fput(file);
+out:
 	return error;
 }
 
+asmlinkage int old_mmap(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	int fd, unsigned long off)
+{
+	if (off & ~PAGE_MASK)
+		return -EINVAL;
+	return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
+}
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc (uint call, int first, int second,
-			int third, void *ptr, long fifth)
+asmlinkage int sys_ipc(uint call, int first, int second,
+		       int third, void *ptr, long fifth)
 {
 	int version, ret;
 
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
--- v2.3.49/linux/arch/sh/kernel/time.c	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/kernel/time.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.7 1999/11/06 02:00:37 gniibe Exp $
+/* $Id: time.c,v 1.20 2000/02/28 12:42:51 gniibe Exp $
  *
  *  linux/arch/sh/kernel/time.c
  *
@@ -8,8 +8,6 @@
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
  */
 
-#include <linux/config.h>
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -43,10 +41,10 @@
 #define TMU0_TCNT	0xfffffe98	/* Long access */
 #define TMU0_TCR	0xfffffe9c	/* Word access */
 
-#define INTERVAL	37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? for CqREEK */
-#if 0 /* Takeshi's board */
-#define INTERVAL	83333
-#endif
+#define FRQCR		0xffffff80
+
+#define RTC_IRQ         22
+#define RTC_IPR_OFFSET  0
 
 /* SH-3 RTC */
 #define R64CNT  	0xfffffec0
@@ -74,7 +72,10 @@
 #define TMU0_TCNT	0xffd8000c	/* Long access */
 #define TMU0_TCR	0xffd80010	/* Word access */
 
-#define INTERVAL	83333
+#define FRQCR		0xffc00000
+
+#define RTC_IRQ		22
+#define RTC_IPR_OFFSET	0
 
 /* SH-4 RTC */
 #define R64CNT  	0xffc80000
@@ -145,11 +146,10 @@
 
 static int set_rtc_time(unsigned long nowtime)
 {
-#ifdef CONFIG_SH_CPU_RTC
 	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
 
-	ctrl_outb(2, RCR2);  /* reset pre-scaler & stop RTC */
+	ctrl_outb(0x02, RCR2);  /* reset pre-scaler & stop RTC */
 
 	cmos_minutes = ctrl_inb(RMINCNT);
 	BCD_TO_BIN(cmos_minutes);
@@ -178,13 +178,9 @@
 		retval = -1;
 	}
 
-	ctrl_outb(2, RCR2);  /* start RTC */
+	ctrl_outb(0x01, RCR2);  /* start RTC */
 
 	return retval;
-#else
-	/* XXX should support other clock devices? */
-	return -1;
-#endif
 }
 
 /* last time the RTC clock got updated */
@@ -197,7 +193,6 @@
 static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
-
 #ifdef TAKESHI
 	{
 		unsigned long what_is_this=0xa4000124;
@@ -248,9 +243,7 @@
 	 * locally disabled. -arca
 	 */
 	write_lock(&xtime_lock);
-
 	do_timer_interrupt(irq, NULL, regs);
-
 	write_unlock(&xtime_lock);
 }
 
@@ -287,11 +280,10 @@
 
 static unsigned long get_rtc_time(void)
 {
-#ifdef CONFIG_SH_CPU_RTC
 	unsigned int sec, min, hr, wk, day, mon, yr, yr100;
 
  again:
-	ctrl_outb(1, RCR1);  /* clear CF bit */
+	ctrl_outb(0x01, RCR1);  /* clear CF bit */
 	do {
 		sec = ctrl_inb(RSECCNT);
 		min = ctrl_inb(RMINCNT);
@@ -321,7 +313,7 @@
 	    hr > 23 || min > 59 || sec > 59) {
 		printk(KERN_ERR
 		       "SH RTC: invalid value, resetting to 1 Jan 2000\n");
-		ctrl_outb(2, RCR2);  /* reset, stop */
+		ctrl_outb(0x02, RCR2);  /* reset, stop */
 		ctrl_outb(0, RSECCNT);
 		ctrl_outb(0, RMINCNT);
 		ctrl_outb(0, RHRCNT);
@@ -333,36 +325,114 @@
 #else
 		ctrl_outb(0, RYRCNT);
 #endif
-		ctrl_outb(1, RCR2);  /* start */
+		ctrl_outb(0x01, RCR2);  /* start */
 		goto again;
 	}
 
 	return mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+}
+
+static __init unsigned int get_cpu_mhz(void)
+{
+	unsigned int count;
+	unsigned long __dummy;
+
+	sti();
+	do {} while (ctrl_inb(R64CNT) != 0);
+	ctrl_outb(0x11, RCR1);
+	asm volatile(
+		"1:\t"
+		"tst	%1,%1\n\t"
+		"bt/s	1b\n\t"
+		" add	#1,%0"
+		: "=&r"(count), "=&z" (__dummy)
+		: "0" (0), "1" (0));
+	cli();
+	/*
+	 * SH-3:
+	 * CPU clock = 4 stages * loop
+	 * tst    rm,rm      if id ex
+	 * bt/s   1b            if id ex
+	 * add    #1,rd            if id ex
+         *                            (if) pipe line stole
+	 * tst    rm,rm                  if id ex
+         * ....
+	 *
+	 *
+	 * SH-4:
+	 * CPU clock = 6 stages * loop
+	 * I don't know why.
+         * ....
+	 */
+#if defined(__SH4__)
+	return count*6;
 #else
-	/* XXX should support other clock devices? */
-	return 0;
+	return count*4;
 #endif
 }
 
+static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ctrl_outb(0x01, RCR1);
+	regs->regs[0] = 1;
+}
+
 static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
+static struct irqaction irq1  = { rtc_interrupt, SA_INTERRUPT, 0, "rtc", NULL, NULL};
 
 void __init time_init(void)
 {
+	unsigned int cpu_clock, master_clock, module_clock;
+	unsigned short ifc, pfc;
+	unsigned long interval;
+#if defined(__sh3__)
+	static int ifc_table[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
+	static int pfc_table[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
+#elif defined(__SH4__)
+	static int ifc_table[] = { 1, 2, 3, 4, 6, 8, 1, 1 };
+	static int pfc_table[] = { 2, 3, 4, 6, 8, 2, 2, 2 };
+#endif
+
 	xtime.tv_sec = get_rtc_time();
 	xtime.tv_usec = 0;
 
-	set_ipr_data(TIMER_IRQ, TIMER_IRP_OFFSET, TIMER_PRIORITY);
+	set_ipr_data(TIMER_IRQ, TIMER_IPR_OFFSET, TIMER_PRIORITY);
 	setup_irq(TIMER_IRQ, &irq0);
+	set_ipr_data(RTC_IRQ, RTC_IPR_OFFSET, TIMER_PRIORITY);
+	setup_irq(RTC_IRQ, &irq1);
 
-	/* Start TMU0 */
-	ctrl_outb(TMU_TOCR_INIT,TMU_TOCR);
-	ctrl_outw(TMU0_TCR_INIT,TMU0_TCR);
-	ctrl_outl(INTERVAL,TMU0_TCOR);
-	ctrl_outl(INTERVAL,TMU0_TCNT);
-	ctrl_outb(TMU_TSTR_INIT,TMU_TSTR);
+	/* Check how fast it is.. */
+	cpu_clock = get_cpu_mhz();
+	disable_irq(RTC_IRQ);
 
-#if 0
-	/* Start RTC */
-	asm volatile("");
+	printk("CPU clock: %d.%02dMHz\n",
+	       (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
+#if defined(__sh3__)
+	{
+		unsigned short tmp;
+		tmp  = (ctrl_inw(FRQCR) & 0x000c) >> 2;
+		tmp |= (ctrl_inw(FRQCR) & 0x4000) >> 12;
+		ifc  = ifc_table[tmp & 0x0007];
+		tmp  = ctrl_inw(FRQCR) & 0x0003;
+		tmp |= (ctrl_inw(FRQCR) & 0x2000) >> 11;
+		pfc = pfc_table[ctrl_inw(FRQCR) & 0x0007];
+	}
+#elif defined(__SH4__)
+	ifc  = ifc_table[(ctrl_inw(FRQCR)>> 6) & 0x0007];
+	pfc = pfc_table[ctrl_inw(FRQCR) & 0x0007];
 #endif
+	master_clock = cpu_clock * ifc;
+	module_clock = master_clock/pfc;
+	printk("Module clock: %d.%02dMHz\n",
+	       (module_clock/1000000), (module_clock % 1000000)/10000);
+	interval = (module_clock/400);
+
+	printk("Interval = %ld\n", interval);
+
+	/* Start TMU0 */
+	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+	ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+	ctrl_outl(interval, TMU0_TCOR);
+	ctrl_outl(interval, TMU0_TCNT);
+	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
 }
diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- v2.3.49/linux/arch/sh/kernel/traps.c	Fri Oct 22 13:21:46 1999
+++ linux/arch/sh/kernel/traps.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.3 1999/09/21 14:37:19 gniibe Exp $
+/* $Id: traps.c,v 1.5 2000/02/27 08:27:55 gniibe Exp $
  *
  *  linux/arch/sh/traps.c
  *
@@ -26,6 +26,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
+#include <asm/processor.h>
 
 static inline void console_verbose(void)
 {
@@ -40,7 +41,7 @@
 { \
 	unsigned long error_code; \
  \
-	asm volatile("stc	r2_bank,%0": "=r" (error_code)); \
+	asm volatile("stc	$r2_bank, %0": "=r" (error_code)); \
 	sti(); \
 	regs.syscall_nr = -1; \
 	tsk->thread.error_code = error_code; \
@@ -99,7 +100,7 @@
 				    struct pt_regs regs)
 {
 	long ex;
-	asm volatile("stc	r2_bank,%0" : "=r" (ex));
+	asm volatile("stc	$r2_bank, %0" : "=r" (ex));
 	die_if_kernel("exception", &regs, ex);
 }
 
@@ -117,8 +118,22 @@
 	   (or P2, virtural "fixed" address space).
 	   It's definitely should not in physical address.  */
 
-	asm volatile("ldc	%0,vbr"
+	asm volatile("ldc	%0, $vbr"
 		     : /* no output */
 		     : "r" (&vbr_base)
 		     : "memory");
+}
+
+void dump_stack(void)
+{
+	unsigned long *start;
+	unsigned long *end;
+	unsigned long *p;
+
+	asm("mov	$r15, %0" : "=r" (start));
+	asm("stc	$r4_bank, %0" : "=r" (end));
+
+	printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end);
+	for (p=start; p < end; p++)
+		printk("%08lx\n", *p);
 }
diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
--- v2.3.49/linux/arch/sh/mm/cache.c	Fri Oct 22 13:21:46 1999
+++ linux/arch/sh/mm/cache.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: cache.c,v 1.7 1999/09/23 11:43:07 gniibe Exp $
+/* $Id: cache.c,v 1.9 2000/02/14 12:45:26 gniibe Exp $
  *
  *  linux/arch/sh/mm/cache.c
  *
@@ -283,7 +283,30 @@
 }
 
 #if defined(__SH4__)
-/* Write back data caches, and invalidates instructiin caches */
+void flush_icache_page(struct vm_area_struct *vma, struct page *pg)
+{
+	unsigned long flags, __dummy;
+	unsigned long addr, data, v;
+
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	v = page_address(pg);
+
+	/* Write back O Cache */
+	asm volatile("ocbwb	%0"
+		     : /* no output */
+		     : "m" (__m(v)));
+	/* Invalidate I Cache */
+	addr = CACHE_IC_ADDRESS_ARRAY |
+		(v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+	data = (v&0xfffffc00); /* Valid=0 */
+	ctrl_outl(data,addr);
+
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
 void flush_icache_range(unsigned long start, unsigned long end)
 {
 	unsigned long flags, __dummy;
@@ -358,7 +381,7 @@
 	flush_cache_range(vma->vm_mm, addr, addr+PAGE_SIZE);
 }
 
-void flush_page_to_ram(unsigned long page)
+void __flush_page_to_ram(unsigned long page)
 {				/* Page is in physical address */
 	/* XXX: for the time being... */
 	flush_cache_all();
diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.3.49/linux/arch/sh/mm/fault.c	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/mm/fault.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.5 1999/10/31 13:17:31 gniibe Exp $
+/* $Id: fault.c,v 1.12 2000/03/01 11:15:27 gniibe Exp $
  *
  *  linux/arch/sh/mm/fault.c
  *  Copyright (C) 1999  Niibe Yutaka
@@ -23,7 +23,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
 
@@ -211,10 +211,12 @@
 		printk(KERN_ALERT "Unable to handle kernel paging request");
 	printk(" at virtual address %08lx\n",address);
 	printk(KERN_ALERT "pc = %08lx\n", regs->pc);
-	page = (unsigned long)mm->pgd;
-	page = ((unsigned long *) __va(page))[address >> 22];
+	asm volatile("mov.l	%1,%0"
+		     : "=r" (page)
+		     : "m" (__m(MMU_TTB)));
+	page = ((unsigned long *) page)[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
-	if (page & 1) {
+	if (page & _PAGE_PRESENT) {
 		page &= PAGE_MASK;
 		address &= 0x003ff000;
 		page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
@@ -256,6 +258,7 @@
 {
 	unsigned long flags;
 	unsigned long pteval;
+	unsigned long pteaddr;
 
 	save_and_cli(flags);
 	/*
@@ -267,6 +270,9 @@
 	pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */
 	/* Set PTEL register */
 	ctrl_outl(pteval, MMU_PTEL);
+	/* Set PTEH register */
+	pteaddr = (address & MMU_VPN_MASK) | (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK);
+	ctrl_outl(pteaddr, MMU_PTEH);
 
 	/* Load the TLB */
 	asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
@@ -277,6 +283,9 @@
 {
 	unsigned long addr, data, asid;
 	unsigned long saved_asid = MMU_NO_ASID;
+#if defined(__SH4__)
+	int i;
+#endif
 
 	if (mm->context == NO_CONTEXT)
 		return;
@@ -296,8 +305,6 @@
 	data = (page & 0xfffe0000) | asid; /* VALID bit is off */
 	ctrl_outl(data, addr);
 #elif defined(__SH4__)
-	int i;
-
 	addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
 	data = page | asid; /* VALID bit is off */
 	ctrl_outl(data, addr);
@@ -305,7 +312,7 @@
 	for (i=0; i<4; i++) {
 		addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
 		data = ctrl_inl(addr);
-		data &= ~0x30;
+		data &= ~0x300;
 		if (data == (page | asid)) {
 			ctrl_outl(data, addr);
 			break;
diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c
--- v2.3.49/linux/arch/sh/mm/init.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/sh/mm/init.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.4 1999/10/23 01:37:02 gniibe Exp gniibe $
+/* $Id: init.c,v 1.16 2000/02/14 15:19:05 gniibe Exp $
  *
  *  linux/arch/sh/mm/init.c
  *
@@ -24,12 +24,14 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
+#include <linux/highmem.h>
 #include <linux/bootmem.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 
@@ -77,13 +79,13 @@
 void __handle_bad_pmd(pmd_t *pmd)
 {
 	pmd_ERROR(*pmd);
-	pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table());
+	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
 }
 
 void __handle_bad_pmd_kernel(pmd_t *pmd)
 {
 	pmd_ERROR(*pmd);
-	pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table());
+	set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
 }
 
 pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
@@ -94,10 +96,10 @@
 	if (pmd_none(*pmd)) {
 		if (pte) {
 			clear_page(pte);
-			pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
+			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
 			return pte + offset;
 		}
-		pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table());
+		set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
 		return NULL;
 	}
 	free_page((unsigned long)pte);
@@ -116,10 +118,10 @@
 	if (pmd_none(*pmd)) {
 		if (pte) {
 			clear_page((void *)pte);
-			pmd_val(*pmd) = _PAGE_TABLE + __pa(pte);
+			set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
 			return (pte_t *)pte + offset;
 		}
-		pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table());
+		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
 		return NULL;
 	}
 	free_page(pte);
@@ -133,15 +135,15 @@
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
-	if(pgtable_cache_size > high) {
+	if (pgtable_cache_size > high) {
 		do {
-			if(pgd_quicklist)
+			if (pgd_quicklist)
 				free_pgd_slow(get_pgd_fast()), freed++;
-			if(pmd_quicklist)
+			if (pmd_quicklist)
 				free_pmd_slow(get_pmd_fast()), freed++;
-			if(pte_quicklist)
+			if (pte_quicklist)
 				free_pte_slow(get_pte_fast()), freed++;
-		} while(pgtable_cache_size > low);
+		} while (pgtable_cache_size > low);
 	}
 	return freed;
 }
@@ -181,6 +183,10 @@
 
 pgd_t swapper_pg_dir[1024];
 
+/* It'd be good if these lines were in the standard header file. */
+#define START_PFN	(NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
+#define MAX_LOW_PFN	(NODE_DATA(0)->bdata->node_low_pfn)
+
 /*
  * paging_init() sets up the page tables
  *
@@ -204,32 +210,55 @@
 	mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
 	set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
 
-	free_area_init(max_low_pfn);
+ 	{
+		unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+		unsigned long max_dma, low, start_pfn;
+
+		start_pfn = START_PFN;
+		max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+		low = MAX_LOW_PFN;
+
+		if (low < max_dma)
+			zones_size[ZONE_DMA] = low - start_pfn;
+		else {
+			zones_size[ZONE_DMA] = max_dma - start_pfn;
+			zones_size[ZONE_NORMAL] = low - max_dma;
+		}
+		free_area_init_node(0, 0, zones_size, __MEMORY_START);
+ 	}
 }
 
 void __init mem_init(void)
 {
-	int codepages = 0;
-	int reservedpages = 0;
-	int datapages = 0;
-	int initpages = 0;
+	int codesize, reservedpages, datasize, initsize;
+	int tmp;
 
-	max_mapnr = num_physpages = max_low_pfn;
-	high_memory = (void *) ((unsigned long)__va(max_low_pfn * PAGE_SIZE)+__MEMORY_START);
+	max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN;
+	high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE);
 
 	/* clear the zero-page */
 	memset(empty_zero_page, 0, PAGE_SIZE);
 
 	/* this will put all low memory onto the freelists */
 	totalram_pages += free_all_bootmem();
+	reservedpages = 0;
+	for (tmp = 0; tmp < num_physpages; tmp++)
+		/*
+		 * Only count reserved RAM pages
+		 */
+		if (PageReserved(mem_map+tmp))
+			reservedpages++;
+	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
+	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
+	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
 	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
-		(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 		max_mapnr << (PAGE_SHIFT-10),
-		codepages << (PAGE_SHIFT-10),
+		codesize >> 10,
 		reservedpages << (PAGE_SHIFT-10),
-		datapages << (PAGE_SHIFT-10),
-		initpages << (PAGE_SHIFT-10));
+		datasize >> 10,
+		initsize >> 10);
 }
 
 void free_initmem(void)
@@ -246,14 +275,28 @@
 	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	unsigned long p;
+	for (p = start; p < end; p += PAGE_SIZE) {
+		ClearPageReserved(mem_map + MAP_NR(p));
+		set_page_count(mem_map+MAP_NR(p), 1);
+		free_page(p);
+		totalram_pages++;
+	}
+	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+}
+#endif
+
 void si_meminfo(struct sysinfo *val)
 {
 	val->totalram = totalram_pages;
 	val->sharedram = 0;
-	val->freeram = nr_free_pages;
+	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
 	val->totalhigh = totalhigh_pages;
-	val->freehigh = nr_free_highpages;
+	val->freehigh = nr_free_highpages();
 	val->mem_unit = PAGE_SIZE;
 	return;
 }
diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c
--- v2.3.49/linux/arch/sh/mm/ioremap.c	Tue Nov 23 22:42:20 1999
+++ linux/arch/sh/mm/ioremap.c	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: ioremap.c,v 1.1 1999/09/18 16:57:48 gniibe Exp $
+/* $Id: ioremap.c,v 1.2 1999/11/25 14:00:28 gniibe Exp $
  *
  * arch/sh/mm/ioremap.c
  *
@@ -11,6 +11,7 @@
 
 #include <linux/vmalloc.h>
 #include <asm/io.h>
+#include <asm/pgalloc.h>
 
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
diff -u --recursive --new-file v2.3.49/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S
--- v2.3.49/linux/arch/sh/vmlinux.lds.S	Fri Oct 22 13:21:46 1999
+++ linux/arch/sh/vmlinux.lds.S	Sun Mar  5 09:33:55 2000
@@ -1,4 +1,4 @@
-/* $Id: vmlinux.lds.S,v 1.3 1999/10/05 12:33:48 gniibe Exp $
+/* $Id: vmlinux.lds.S,v 1.4 1999/12/23 11:37:45 gniibe Exp $
  * ld script to make SuperH Linux kernel
  * Written by Niibe Yutaka
  */
@@ -13,8 +13,8 @@
 SECTIONS
 {
   . = 0x80000000 + CONFIG_MEMORY_START + 0x1000;
-  __text = .;			/* Text and read-only data */
   _text = .;			/* Text and read-only data */
+  text = .;			/* Text and read-only data */
   .text : {
 	*(.empty_zero_page)
 	*(.text)
@@ -26,41 +26,41 @@
   .kstrtab : { *(.kstrtab) }
 
   . = ALIGN(16);		/* Exception table */
-  ___start___ex_table = .;
-  ___ex_table : { *(__ex_table) }
-  ___stop___ex_table = .;
-
-  ___start___ksymtab = .;	/* Kernel symbol table */
-  ___ksymtab : { *(__ksymtab) }
-  ___stop___ksymtab = .;
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
 
-  __etext = .;			/* End of text section */
+  _etext = .;			/* End of text section */
 
   .data : {			/* Data */
 	*(.data)
 	CONSTRUCTORS
 	}
 
-  __edata = .;			/* End of data section */
+  _edata = .;			/* End of data section */
 
   . = ALIGN(8192);		/* init_task */
   .data.init_task : { *(.data.init_task) }
   /* stack */
-  .stack : { _stack = .;  __stack = .; }
+  .stack : { stack = .;  _stack = .; }
 
   . = ALIGN(4096);		/* Init code and data */
-  ___init_begin = .;
+  __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
   . = ALIGN(16);
-  ___setup_start = .;
+  __setup_start = .;
   .setup.init : { *(.setup.init) }
-  ___setup_end = .;
-  ___initcall_start = .;
+  __setup_end = .;
+  __initcall_start = .;
   .initcall.init : { *(.initcall.init) }
-  ___initcall_end = .;
+  __initcall_end = .;
   . = ALIGN(4096);
-  ___init_end = .;
+  __init_end = .;
 
   . = ALIGN(4096);
   .data.page_aligned : { *(.data.idt) }
@@ -69,12 +69,12 @@
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   . = ALIGN(4);
-  ___bss_start = .;		/* BSS */
+  __bss_start = .;		/* BSS */
   .bss : {
 	*(.bss)
 	}
   . = ALIGN(4);
-  __end = . ;
+  _end = . ;
 
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
diff -u --recursive --new-file v2.3.49/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.49/linux/arch/sparc/kernel/sys_sunos.c	Sun Feb 20 21:12:38 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Mar  6 15:49:21 2000
@@ -432,12 +432,10 @@
 asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
 {
 	struct file * file;
-	struct inode * inode;
 	struct sunos_dirent * lastdirent;
 	struct sunos_dirent_callback buf;
 	int error = -EBADF;
 
-	lock_kernel();
 	if (fd >= SUNOS_NR_OPEN)
 		goto out;
 
@@ -445,10 +443,7 @@
 	if (!file)
 		goto out;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
+	lock_kernel();
 	error = -EINVAL;
 	if (cnt < (sizeof(struct sunos_dirent) + 255))
 		goto out_putf;
@@ -458,10 +453,7 @@
 	buf.count = cnt;
 	buf.error = 0;
 
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, sunos_filldir);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, sunos_filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 
@@ -473,9 +465,9 @@
 	}
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -521,12 +513,10 @@
 asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
 {
 	struct file * file;
-	struct inode * inode;
 	struct sunos_direntry * lastdirent;
 	struct sunos_direntry_callback buf;
 	int error = -EBADF;
 
-	lock_kernel();
 	if (fd >= SUNOS_NR_OPEN)
 		goto out;
 
@@ -534,10 +524,7 @@
 	if (!file)
 		goto out;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
+	lock_kernel();
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_direntry) + 255))
 		goto out_putf;
@@ -547,10 +534,7 @@
 	buf.count = cnt;
 	buf.error = 0;
 
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, sunos_filldirentry);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, sunos_filldirentry, &buf);
 	if (error < 0)
 		goto out_putf;
 
@@ -562,9 +546,9 @@
 	}
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.3.49/linux/arch/sparc64/kernel/entry.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc64/kernel/entry.S	Tue Mar  7 11:05:48 2000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.112 2000/01/14 07:12:31 davem Exp $
+/* $Id: entry.S,v 1.113 2000/03/06 22:33:42 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -927,7 +927,17 @@
 		 nop
 		ldx		[%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7
 		wr		%g0, %o7, %pcr
-		wr		%g0, %g0, %pic
+
+		/* Blackbird errata workaround.  See commentary in
+		 * smp.c:smp_percpu_timer_interrupt() for more
+		 * information.
+		 */
+		ba,pt		%xcc, 99f
+		 nop
+		.align		64
+99:		wr		%g0, %g0, %pic
+		rd		%pic, %g0
+
 1:		b,pt		%xcc, ret_sys_call
 		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 sparc_exit:	rdpr		%otherwin, %g1
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.3.49/linux/arch/sparc64/kernel/head.S	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/head.S	Tue Mar  7 11:05:48 2000
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.63 1999/11/19 05:52:49 davem Exp $
+/* $Id: head.S,v 1.64 2000/03/06 22:33:42 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -262,7 +262,16 @@
 
 	/* Setup "Linux Current Register", thanks Sun 8-) */
 	wr	%g0, 0x1, %pcr
-	wr	%g6, 0x0, %pic
+
+	/* Blackbird errata workaround.  See commentary in
+	 * smp.c:smp_percpu_timer_interrupt() for more
+	 * information.
+	 */
+	ba,pt	%xcc, 99f
+	 nop
+	.align	64
+99:	wr	%g6, %g0, %pic
+	rd	%pic, %g0
 #endif
 
 	wr	%g0, ASI_P, %asi
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.3.49/linux/arch/sparc64/kernel/setup.c	Sat Feb 26 22:31:42 2000
+++ linux/arch/sparc64/kernel/setup.c	Fri Mar  3 21:29:24 2000
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $
+/*  $Id: setup.c,v 1.52 2000/03/03 23:48:41 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -164,9 +164,17 @@
 		}
 
 		if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 			/*
 			 * Locked down tlb entry 63.
 			 */
+
 			tte = spitfire_get_dtlb_data(63);
 			res = PROM_TRUE;
 			goto done;
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.49/linux/arch/sparc64/kernel/smp.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/sparc64/kernel/smp.c	Tue Mar  7 11:10:54 2000
@@ -312,6 +312,13 @@
 	       smp_processor_id(), data0, data1, data2, target);
 #endif
 again:
+	/* Ok, this is the real Spitfire Errata #54.
+	 * One must read back from a UDB internal register
+	 * after writes to the UDB interrupt dispatch, but
+	 * before the membar Sync for that write.
+	 * So we use the high UDB control register (ASI 0x7f,
+	 * ADDR 0x20) for the dummy read. -DaveM
+	 */
 	tmp = 0x40;
 	__asm__ __volatile__("
 	wrpr	%1, %2, %%pstate
@@ -321,10 +328,13 @@
 	stxa	%6, [%0+%8] %3
 	membar	#Sync
 	stxa	%%g0, [%7] %3
+	mov	0x20, %%g1
+	ldxa	[%%g1] 0x7f, %%g0
 	membar	#Sync"
 	: "=r" (tmp)
 	: "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
-	  "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp));
+	  "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp)
+       : "g1");
 
 	/* NOTE: PSTATE_IE is still clear. */
 	stuck = 100000;
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.49/linux/arch/sparc64/kernel/sys_sparc32.c	Thu Mar  2 14:36:22 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Mar  6 15:49:21 2000
@@ -1257,10 +1257,8 @@
 {
 	int error = -EBADF;
 	struct file * file;
-	struct inode * inode;
 	struct readdir_callback32 buf;
 
-	lock_kernel();
 	file = fget(fd);
 	if (!file)
 		goto out;
@@ -1268,22 +1266,16 @@
 	buf.count = 0;
 	buf.dirent = dirent;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-	
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, fillonedir);
-	up(&inode->i_sem);
+	lock_kernel();
+	error = vfs_readdir(file, fillonedir, &buf);
 	if (error < 0)
 		goto out_putf;
 	error = buf.count;
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -1328,12 +1320,10 @@
 asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
 {
 	struct file * file;
-	struct inode * inode;
 	struct linux_dirent32 * lastdirent;
 	struct getdents_callback32 buf;
 	int error = -EBADF;
 
-	lock_kernel();
 	file = fget(fd);
 	if (!file)
 		goto out;
@@ -1343,14 +1333,8 @@
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, filldir);
-	up(&inode->i_sem);
+	lock_kernel();
+	error = vfs_readdir(file, filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 	lastdirent = buf.previous;
@@ -1360,9 +1344,9 @@
 		error = count - buf.count;
 	}
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.49/linux/arch/sparc64/kernel/sys_sunos32.c	Sun Feb 20 21:12:38 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Mar  6 15:49:21 2000
@@ -388,13 +388,11 @@
 asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
 {
 	struct file * file;
-	struct inode * inode;
 	struct sunos_dirent * lastdirent;
 	struct sunos_dirent_callback buf;
 	int error = -EBADF;
 	void *dirent = (void *)A(u_dirent);
 
-	lock_kernel();
 	if(fd >= SUNOS_NR_OPEN)
 		goto out;
 
@@ -402,9 +400,7 @@
 	if(!file)
 		goto out;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
+	lock_kernel();
 
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_dirent) + 255))
@@ -415,10 +411,7 @@
 	buf.count = cnt;
 	buf.error = 0;
 
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, sunos_filldir);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, sunos_filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 
@@ -430,9 +423,9 @@
 	}
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -481,12 +474,10 @@
 	void *dirent = (void *) A(u_dirent);
 	unsigned int *basep = (unsigned int *)A(u_basep);
 	struct file * file;
-	struct inode * inode;
 	struct sunos_direntry * lastdirent;
 	int error = -EBADF;
 	struct sunos_direntry_callback buf;
 
-	lock_kernel();
 	if(fd >= SUNOS_NR_OPEN)
 		goto out;
 
@@ -494,9 +485,7 @@
 	if(!file)
 		goto out;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
+	lock_kernel();
 
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_direntry) + 255))
@@ -507,10 +496,7 @@
 	buf.count = cnt;
 	buf.error = 0;
 
-	inode = file->f_dentry->d_inode;
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, sunos_filldirentry);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, sunos_filldirentry, &buf);
 	if (error < 0)
 		goto out_putf;
 
@@ -522,9 +508,9 @@
 	}
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.3.49/linux/arch/sparc64/lib/blockops.S	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/lib/blockops.S	Fri Mar  3 21:29:24 2000
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.19 1999/11/19 05:52:45 davem Exp $
+/* $Id: blockops.S,v 1.20 2000/03/03 23:48:38 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -46,13 +46,37 @@
 	sethi		%hi(TLBTEMP_ENT1), %o3
 	rdpr		%pstate, %g3
 	wrpr		%g3, PSTATE_IE, %pstate
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %o4
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %o5
+	stxa		%g0, [%o5] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %o5
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 	add		%o3, (TLBTEMP_ENTSZ), %o3
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g5
+	stxa		%g0, [%g5] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o1, [%o2] ASI_DMMU
 	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
@@ -120,7 +144,19 @@
 	sethi		%hi(TLBTEMP_ENT2), %o3
 	rdpr		%pstate, %g3
 	wrpr		%g3, PSTATE_IE, %pstate
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g5
+	stxa		%g0, [%g5] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.49/linux/arch/sparc64/mm/init.c	Thu Feb 10 17:11:06 2000
+++ linux/arch/sparc64/mm/init.c	Fri Mar  3 21:29:24 2000
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.146 2000/02/09 21:11:09 davem Exp $
+/*  $Id: init.c,v 1.147 2000/03/03 23:48:44 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -230,6 +230,14 @@
 
 	/* Now fixup OBP's idea about where we really are mapped. */
 	prom_printf("Remapping the kernel... ");
+
+	/* Spitfire Errata #32 workaround */
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "flush	%%g6"
+			     : /* No outputs */
+			     : "r" (0),
+			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 	phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
 	phys_page += ((unsigned long)&prom_boot_page -
 		      (unsigned long)&empty_zero_page);
@@ -252,11 +260,27 @@
 		: "memory");
 
 	tte_vaddr = (unsigned long) &empty_zero_page;
+
+	/* Spitfire Errata #32 workaround */
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "flush	%%g6"
+			     : /* No outputs */
+			     : "r" (0),
+			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 	kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
 
 	remap_func = (void *)  ((unsigned long) &prom_remap -
 				(unsigned long) &prom_boot_page);
 
+
+	/* Spitfire Errata #32 workaround */
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "flush	%%g6"
+			     : /* No outputs */
+			     : "r" (0),
+			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 	remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
 		   (unsigned long) &empty_zero_page,
 		   prom_get_mmu_ihandle());
@@ -319,8 +343,16 @@
 
 	/* Only DTLB must be checked for VPTE entries. */
 	for(i = 0; i < 63; i++) {
-		unsigned long tag = spitfire_get_dtlb_tag(i);
+		unsigned long tag;
 
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+		tag = spitfire_get_dtlb_tag(i);
 		if(((tag & ~(PAGE_MASK)) == 0) &&
 		   ((tag &  (PAGE_MASK)) >= prom_reserved_base)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -436,10 +468,26 @@
 	for(i = 0; i < 63; i++) {
 		unsigned long data;
 
+
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		data = spitfire_get_dtlb_data(i);
 		if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-			unsigned long tag = spitfire_get_dtlb_tag(i);
+			unsigned long tag;
+
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
+			tag = spitfire_get_dtlb_tag(i);
 			if(save_p) {
 				prom_dtlb[dtlb_seen].tlb_ent = i;
 				prom_dtlb[dtlb_seen].tlb_tag = tag;
@@ -459,10 +507,25 @@
 	for(i = 0; i < 63; i++) {
 		unsigned long data;
 
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		data = spitfire_get_itlb_data(i);
 		if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-			unsigned long tag = spitfire_get_itlb_tag(i);
+			unsigned long tag;
+
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
+			tag = spitfire_get_itlb_tag(i);
 			if(save_p) {
 				prom_itlb[itlb_seen].tlb_ent = i;
 				prom_itlb[itlb_seen].tlb_tag = tag;
@@ -544,6 +607,13 @@
 			     : "=r" (pstate)
 			     : "i" (PSTATE_IE));
 	for(i = 0; i < 64; i++) {
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : /* no outputs */
@@ -552,6 +622,14 @@
 			spitfire_put_dtlb_data(i, 0x0UL);
 			membar("#Sync");
 		}
+
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		if(!(spitfire_get_itlb_data(i) & _PAGE_L)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : /* no outputs */
diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.3.49/linux/arch/sparc64/mm/ultra.S	Wed Feb 16 17:03:51 2000
+++ linux/arch/sparc64/mm/ultra.S	Fri Mar  3 21:29:24 2000
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.37 2000/02/14 02:52:04 davem Exp $
+/* $Id: ultra.S,v 1.38 2000/03/03 23:48:44 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -35,7 +35,7 @@
 __flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
 		    * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
 		    */
-#define TLB_MAGIC	206 /* Students, do you know how I calculated this?  -DaveM */
+#define TLB_MAGIC	207 /* Students, do you know how I calculated this?  -DaveM */
 /*IC3*/	cmp		%o5, %o4
 	be,pt		%xcc, __flush_tlb_page
 	 srlx		%o5, 13, %g5
@@ -58,6 +58,12 @@
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
 	mov		(62 << 3), %g2
+
+	/* Spitfire Errata #32 workaround. */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 1:	ldxa		[%g2] ASI_ITLB_TAG_READ, %o4
 	and		%o4, 0x3ff, %o5
 	cmp		%o5, %o0
@@ -83,12 +89,27 @@
 	 wrpr		%g1, 0x0, %pstate
 4:	stxa		%g0, [%g3] ASI_IMMU
 	stxa		%g0, [%g2] ASI_ITLB_DATA_ACCESS
+	flush		%g6
+
+	/* Spitfire Errata #32 workaround. */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 	ba,pt		%xcc, 2b
-	 flush		%g6
+	 nop
+
 5:	stxa		%g0, [%g3] ASI_DMMU
 /*IC9*/	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
+	flush		%g6
+
+	/* Spitfire Errata #32 workaround. */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 	ba,pt		%xcc, 3b
-	 flush		%g6
+	 nop
 
 	.align		32
 __flush_tlb_mm_slow:
@@ -293,28 +314,51 @@
 	 clr		%l6
 99:	retry
 
+	.data
+
+errata32_hwbug:
+	.xword	0
+
+	.text
+
 	/* These two are not performance critical... */
 	.globl		xcall_flush_tlb_all
 xcall_flush_tlb_all:
+
+	/* Spitfire Errata #32 workaround. */
+	sethi		%hi(errata32_hwbug), %g4
+	stx		%g0, [%g4 + %lo(errata32_hwbug)]
+
 	clr		%g2
 	clr		%g3
 1:	ldxa		[%g3] ASI_DTLB_DATA_ACCESS, %g4
 	and		%g4, _PAGE_L, %g5
 	brnz,pn		%g5, 2f
 	 mov		TLB_TAG_ACCESS, %g7
+
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
-
 	stxa		%g0, [%g3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
+
+	/* Spitfire Errata #32 workaround. */
+	sethi		%hi(errata32_hwbug), %g4
+	stx		%g0, [%g4 + %lo(errata32_hwbug)]
+
 2:	ldxa		[%g3] ASI_ITLB_DATA_ACCESS, %g4
 	and		%g4, _PAGE_L, %g5
 	brnz,pn		%g5, 2f
 	 mov		TLB_TAG_ACCESS, %g7
+
 	stxa		%g0, [%g7] ASI_IMMU
 	membar		#Sync
-
 	stxa		%g0, [%g3] ASI_ITLB_DATA_ACCESS
+	membar		#Sync
+
+	/* Spitfire Errata #32 workaround. */
+	sethi		%hi(errata32_hwbug), %g4
+	stx		%g0, [%g4 + %lo(errata32_hwbug)]
+
 2:	add		%g2, 1, %g2
 	cmp		%g2, 63
 	ble,pt		%icc, 1b
diff -u --recursive --new-file v2.3.49/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.49/linux/drivers/block/Config.in	Thu Mar  2 14:36:22 2000
+++ linux/drivers/block/Config.in	Fri Mar  3 12:54:45 2000
@@ -213,9 +213,9 @@
 #   tristate '  RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
 #   tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5
 fi
-if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
-fi
+#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
+#   bool '    Boot support (linear, striped)' CONFIG_MD_BOOT
+#fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
    bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
diff -u --recursive --new-file v2.3.49/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c
--- v2.3.49/linux/drivers/block/ali14xx.c	Sat Feb 26 22:31:43 2000
+++ linux/drivers/block/ali14xx.c	Fri Mar  3 12:54:44 2000
@@ -55,12 +55,12 @@
 
 /* port addresses for auto-detection */
 #define ALI_NUM_PORTS 4
-static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
 
 /* register initialization data */
 typedef struct { byte reg, data; } RegInitializer;
 
-static RegInitializer __init initData[] = {
+static RegInitializer initData[] __initdata = {
 	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
 	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
 	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
diff -u --recursive --new-file v2.3.49/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h
--- v2.3.49/linux/drivers/block/cpqarray.h	Thu Mar  2 14:36:22 2000
+++ linux/drivers/block/cpqarray.h	Fri Mar  3 12:54:44 2000
@@ -30,7 +30,6 @@
 #include <linux/locks.h>
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
-#include <linux/raid/md.h>
 #include <linux/timer.h>
 #endif
 
diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.3.49/linux/drivers/block/ide-cd.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/block/ide-cd.c	Fri Mar  3 12:59:50 2000
@@ -1883,7 +1883,7 @@
 	char buffer[16];
 	int stat;
 
-	init_cdrom_command(&cgc, buffer, sizeof(buffer));
+	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
 
 	/* These will be moved into the Uniform layer shortly... */
 	switch (cmd) {
@@ -2075,7 +2075,7 @@
 	if ((stat = cdrom_select_speed (drive, speed)) < 0)
 		return stat;
 
-	init_cdrom_command(&cgc, &buf, sizeof(buf));
+	init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
 
 #ifndef __ACER50__
 	/* Now with that done, update the speed fields */
@@ -2303,7 +2303,7 @@
 		return nslots;
 	}
 
-	init_cdrom_command(&cgc, &buf, sizeof(buf));
+	init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
 	/* we have to cheat a little here. the packet will eventually
 	 * be queued with ide_cdrom_packet(), which extracts the
 	 * drive from cdi->handle. Since this device hasn't been
diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.49/linux/drivers/block/ide-pmac.c	Thu Feb 10 17:11:07 2000
+++ linux/drivers/block/ide-pmac.c	Thu Mar  2 22:46:07 2000
@@ -420,7 +420,7 @@
 		hwif = &ide_hwifs[i];
 		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
 		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-		hwif->chipset = ide_generic;
+		hwif->chipset = ide_pmac;
 		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.49/linux/drivers/block/ide-probe.c	Sat Feb 26 22:31:43 2000
+++ linux/drivers/block/ide-probe.c	Tue Mar  7 11:07:42 2000
@@ -686,6 +686,7 @@
 	struct gendisk *gd, **gdp;
 	unsigned int unit, units, minors;
 	int *bs, *max_sect, *max_ra;
+	extern devfs_handle_t ide_devfs_handle;
 
 	/* figure out maximum drive number on the interface */
 	for (units = MAX_DRIVES; units > 0; --units) {
@@ -742,11 +743,11 @@
 			char name[64];
 
 			ide_add_generic_settings(hwif->drives + unit);
-			sprintf (name, "ide/host%d/bus%d/target%d/lun%d",
-				 hwif->channel ? hwif->mate->index : hwif->index,
+			sprintf (name, "host%d/bus%d/target%d/lun%d",
+				 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
 				 hwif->channel, unit, 0);
 			hwif->drives[unit].de =
-				devfs_mk_dir (NULL, name, 0, NULL);
+				devfs_mk_dir (ide_devfs_handle, name, 0, NULL);
 		}
 	}
 }
diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
--- v2.3.49/linux/drivers/block/ide-proc.c	Sat Feb 26 22:31:43 2000
+++ linux/drivers/block/ide-proc.c	Thu Mar  2 22:46:07 2000
@@ -405,6 +405,7 @@
 		case ide_cmd646:	name = "cmd646";	break;
 		case ide_cy82c693:	name = "cy82c693";	break;
 		case ide_4drives:	name = "4drives";	break;
+		case ide_pmac:		name = "mac-io";	break;
 		default:		name = "(unknown)";	break;
 	}
 	len = sprintf(page, "%s\n", name);
diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.49/linux/drivers/block/ide.c	Sat Feb 26 22:31:44 2000
+++ linux/drivers/block/ide.c	Tue Mar  7 11:07:42 2000
@@ -143,6 +143,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -3456,6 +3457,8 @@
 /*
  * Probe module
  */
+devfs_handle_t ide_devfs_handle = NULL;
+
 EXPORT_SYMBOL(ide_probe);
 EXPORT_SYMBOL(drive_is_flashcard);
 EXPORT_SYMBOL(ide_timer_expiry);
@@ -3464,6 +3467,7 @@
 EXPORT_SYMBOL(ide_get_queue);
 EXPORT_SYMBOL(do_ide0_request);
 EXPORT_SYMBOL(ide_add_generic_settings);
+EXPORT_SYMBOL(ide_devfs_handle);
 #if MAX_HWIFS > 1
 EXPORT_SYMBOL(do_ide1_request);
 #endif /* MAX_HWIFS > 1 */
@@ -3545,6 +3549,7 @@
 
 	if (!banner_printed) {
 		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
+		ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL);
 		banner_printed = 1;
 	}
 
@@ -3602,6 +3607,7 @@
 #ifdef CONFIG_PROC_FS
 	proc_ide_destroy();
 #endif
+	devfs_unregister (ide_devfs_handle);
 }
 
 #else /* !MODULE */
diff -u --recursive --new-file v2.3.49/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.3.49/linux/drivers/block/nbd.c	Sun Feb 20 21:12:38 2000
+++ linux/drivers/block/nbd.c	Fri Mar  3 21:28:38 2000
@@ -77,6 +77,7 @@
 	nbd_dev[dev].refcnt++;
 	if (!(nbdev->flags & NBD_INITIALISED)) {
 		init_MUTEX(&nbdev->queue_lock);
+		INIT_LIST_HEAD(&nbdev->queue_head);
 		nbdev->flags |= NBD_INITIALISED;
 	}
 	MOD_INC_USE_COUNT;
diff -u --recursive --new-file v2.3.49/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.49/linux/drivers/cdrom/cdrom.c	Wed Feb 16 17:03:51 2000
+++ linux/drivers/cdrom/cdrom.c	Fri Mar  3 12:59:50 2000
@@ -187,14 +187,23 @@
   -- Fixed CDDA ripping with cdda2wav - accept much larger requests of
   number of frames and split the reads in blocks of 8.
 
-  3.05 Dec 13, 1999 - Jens Axboe <axboe@image.dk>
+  3.06 Dec 13, 1999 - Jens Axboe <axboe@image.dk>
   -- Added support for changing the region of DVD drives.
   -- Added sense data to generic command.
+
+  3.07 Feb 2, 2000 - Jens Axboe <axboe@suse.de>
+  -- Do same "read header length" trick in cdrom_get_disc_info() as
+  we do in cdrom_get_track_info() -- some drive don't obbey specs and
+  fail if they can't supply the full Mt Fuji size table.
+  -- Deleted stuff related to setting up write modes. It has a different
+  home now.
+  -- Clear header length in mode_select unconditionally.
+  -- Removed the register_disk() that was added, not needed here.
   
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 3.06"
-#define VERSION "Id: cdrom.c 3.06 1999/12/13"
+#define REVISION "Revision: 3.07"
+#define VERSION "Id: cdrom.c 3.07 2000/02/02"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -415,7 +424,6 @@
 	return 0;
 }
 
-static
 struct cdrom_device_info *cdrom_find_device(kdev_t dev)
 {
 	struct cdrom_device_info *cdi;
@@ -682,7 +690,7 @@
 	length = sizeof(struct cdrom_mechstat_header) +
 		 cdi->capacity * sizeof(struct cdrom_slot);
 
-	init_cdrom_command(&cgc, buf, length);
+	init_cdrom_command(&cgc, buf, length, CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_MECHANISM_STATUS;
 	cgc.cmd[8] = (length >> 8) & 0xff;
 	cgc.cmd[9] = length & 0xff;
@@ -737,7 +745,7 @@
 	if (cdi->sanyo_slot && slot < 0)
 		return 0;
 
-	init_cdrom_command(&cgc, NULL, 0);
+	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
 	cgc.cmd[0] = GPCMD_LOAD_UNLOAD;
 	cgc.cmd[4] = 2 + (slot >= 0);
 	cgc.cmd[8] = slot;
@@ -921,12 +929,15 @@
 	*curr = requested;
 }
 
-void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len)
+void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len,
+			int type)
 {
 	memset(cgc, 0, sizeof(struct cdrom_generic_command));
-	memset(buf, 0, len);
+	if (buf)
+		memset(buf, 0, len);
 	cgc->buffer = (char *) buf;
 	cgc->buflen = len;
+	cgc->data_direction = type;
 }
 
 /* DVD handling */
@@ -953,6 +964,7 @@
 		}
 	}
 	cgc->cmd[9] = cgc->buflen;
+	cgc->data_direction = CGC_DATA_WRITE;
 }
 
 static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
@@ -974,6 +986,7 @@
 		}
 	}
 	cgc->cmd[9] = cgc->buflen;
+	cgc->data_direction = CGC_DATA_READ;
 }
 
 static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
@@ -983,7 +996,7 @@
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
 
-	init_cdrom_command(&cgc, buf, 0);
+	init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ);
 
 	switch (ai->type) {
 	/* LU data send */
@@ -1124,7 +1137,7 @@
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
 
-	init_cdrom_command(&cgc, buf, sizeof(buf));
+	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
 	cgc.cmd[6] = s->physical.layer_num;
 	cgc.cmd[7] = s->type;
@@ -1165,7 +1178,7 @@
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
 
-	init_cdrom_command(&cgc, buf, sizeof(buf));
+	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
 	cgc.cmd[6] = s->copyright.layer_num;
 	cgc.cmd[7] = s->type;
@@ -1193,7 +1206,7 @@
 	if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
-	init_cdrom_command(&cgc, buf, size);
+	init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
 	cgc.cmd[7] = s->type;
 	cgc.cmd[8] = size >> 8;
@@ -1214,7 +1227,7 @@
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
 
-	init_cdrom_command(&cgc, buf, sizeof(buf));
+	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
 	cgc.cmd[7] = s->type;
 	cgc.cmd[9] = cgc.buflen = 0xff;
@@ -1244,7 +1257,7 @@
 	if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
-	init_cdrom_command(&cgc, buf, size);
+	init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
 	cgc.cmd[7] = s->type;
 	cgc.cmd[8] = size >> 8;
@@ -1305,6 +1318,7 @@
 	cgc->cmd[2] = page_code | (page_control << 6);
 	cgc->cmd[7] = cgc->buflen >> 8;
 	cgc->cmd[8] = cgc->buflen & 0xff;
+	cgc->data_direction = CGC_DATA_READ;
 	return cdo->generic_packet(cdi, cgc);
 }
 
@@ -1314,11 +1328,12 @@
 	struct cdrom_device_ops *cdo = cdi->ops;
 
 	memset(cgc->cmd, 0, sizeof(cgc->cmd));
-	
+	memset(cgc->buffer, 0, 2);
 	cgc->cmd[0] = GPCMD_MODE_SELECT_10;
 	cgc->cmd[1] = 0x10;		/* PF */
 	cgc->cmd[7] = cgc->buflen >> 8;
 	cgc->cmd[8] = cgc->buflen & 0xff;
+	cgc->data_direction = CGC_DATA_WRITE;
 	return cdo->generic_packet(cdi, cgc);
 }
 
@@ -1330,7 +1345,7 @@
 	char buffer[32];
 	int ret;
 
-	init_cdrom_command(&cgc, buffer, 16);
+	init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
 	cgc.cmd[1] = 2;     /* MSF addressing */
 	cgc.cmd[2] = 0x40;  /* request subQ data */
@@ -1812,6 +1827,7 @@
 		cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);
 		if (cgc.buffer == NULL)
 			return -ENOMEM;
+		cgc.data_direction = CGC_DATA_READ;
 		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
 		if (!ret)
 			if (copy_to_user((char *)arg, cgc.buffer, blocksize))
@@ -1849,7 +1865,7 @@
 			kfree(cgc.buffer);
 			return -EFAULT;
 		}
-
+		cgc.data_direction = CGC_DATA_READ;
 		while (ra.nframes > 0) {
 			ret = cdrom_read_block(cdi, &cgc, lba, frames, 1,
 					       CD_FRAMESIZE_RAW);
@@ -1913,6 +1929,7 @@
 		cgc.cmd[7] = entry.cdte_addr.msf.second;
 		cgc.cmd[8] = entry.cdte_addr.msf.frame;
 		cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
 	case CDROMPLAYMSF: {
@@ -1926,6 +1943,7 @@
 		cgc.cmd[6] = msf.cdmsf_min1;
 		cgc.cmd[7] = msf.cdmsf_sec1;
 		cgc.cmd[8] = msf.cdmsf_frame1;
+		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
 	case CDROMPLAYBLK: {
@@ -1939,6 +1957,7 @@
 		cgc.cmd[5] = blk.from & 0xff;
 		cgc.cmd[7] = (blk.len >> 8) & 0xff;
 		cgc.cmd[8] = blk.len & 0xff;
+		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
 	case CDROMVOLCTRL:
@@ -1989,9 +2008,6 @@
 		buffer[offset+13] = volctrl.channel2 & mask[offset+13];
 		buffer[offset+15] = volctrl.channel3 & mask[offset+15];
 
-		/* clear the first three */
-		memset(buffer, 0, 3);
-
 		/* set volume */
 		cgc.buffer = buffer;
 		return cdrom_mode_select(cdi, &cgc);
@@ -2003,6 +2019,7 @@
 		cgc.cmd[0] = GPCMD_START_STOP_UNIT;
 		cgc.cmd[1] = 1;
 		cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
+		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
 
@@ -2011,6 +2028,7 @@
 		cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 
 		cgc.cmd[0] = GPCMD_PAUSE_RESUME;
 		cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
+		cgc.data_direction = CGC_DATA_NONE;
 		return cdo->generic_packet(cdi, &cgc);
 		}
 
@@ -2090,7 +2108,7 @@
 		if (copy && !ret)
 			__copy_to_user(userbuf, cgc.buffer, cgc.buflen);
 		/* copy back sense data */
-		if (ret && sense != NULL)
+		if (sense != NULL)
 			if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense)))
 				ret = -EFAULT;
 		kfree(cgc.buffer);
@@ -2125,7 +2143,7 @@
 	struct cdrom_generic_command cgc;
 	int ret;
 
-	init_cdrom_command(&cgc, ti, 8);
+	init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
 	cgc.cmd[1] = type & 3;
 	cgc.cmd[4] = (track & 0xff00) >> 8;
@@ -2145,12 +2163,26 @@
 	struct cdrom_device_info *cdi = cdrom_find_device(dev);
 	struct cdrom_device_ops *cdo = cdi->ops;
 	struct cdrom_generic_command cgc;
+	int ret;
 
 	/* set up command and get the disc info */
-	init_cdrom_command(&cgc, di, sizeof(*di));
+	init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DISC_INFO;
-	cgc.cmd[8] = cgc.buflen;
+	cgc.cmd[8] = cgc.buflen = 2;
 
+	if ((ret = cdo->generic_packet(cdi, &cgc)))
+		return ret;
+
+	/* not all drives have the same disc_info length, so requeue
+	 * packet with the length the drive tells us it can supply
+	 */
+	cgc.buflen = be16_to_cpu(di->disc_information_length) +
+		     sizeof(di->disc_information_length);
+
+	if (cgc.buflen > sizeof(disc_information))
+		cgc.buflen = sizeof(disc_information);
+
+	cgc.cmd[8] = cgc.buflen;
 	return cdo->generic_packet(cdi, &cgc);
 }
 
@@ -2265,6 +2297,7 @@
 EXPORT_SYMBOL(cdrom_mode_select);
 EXPORT_SYMBOL(cdrom_mode_sense);
 EXPORT_SYMBOL(init_cdrom_command);
+EXPORT_SYMBOL(cdrom_find_device);
 
 #ifdef CONFIG_SYSCTL
 
diff -u --recursive --new-file v2.3.49/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.49/linux/drivers/char/Config.in	Thu Mar  2 14:36:22 2000
+++ linux/drivers/char/Config.in	Mon Mar  6 15:32:30 2000
@@ -197,7 +197,9 @@
       hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
    fi
    comment 'Video Adapters'
-   dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI
+   if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then
+      dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT
+   fi
    dep_tristate '  Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
    if [ "$CONFIG_PARPORT" != "n" ]; then
       dep_tristate '  Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
diff -u --recursive --new-file v2.3.49/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.49/linux/drivers/char/Makefile	Thu Mar  2 14:36:22 2000
+++ linux/drivers/char/Makefile	Mon Mar  6 15:32:30 2000
@@ -38,7 +38,7 @@
 
 export-objs     :=	busmouse.o console.o i2c-old.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o videodev.o \
-			tty_io.o
+			tty_io.o bttv.o
 
 KEYMAP   =defkeymap.o
 KEYBD    =pc_keyb.o
@@ -61,6 +61,20 @@
   SERIAL   =
 endif
 
+ifeq ($(ARCH),sh)
+  KEYMAP   =
+  KEYBD    =
+  CONSOLE  =
+  SERIAL =
+  ifeq ($(CONFIG_SERIAL),y)
+  SERIAL = generic_serial.o sh-sci.o
+  else
+    ifeq ($(CONFIG_SERIAL),m)
+    SERIAL = sh-sci.o
+    endif
+  endif
+endif
+
 ifeq ($(CONFIG_DECSTATION),y)
   KEYBD    =
   SERIAL   =
@@ -180,13 +194,11 @@
   endif
 endif
 
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o
+obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda985x.o tea6300.o
 ifeq ($(CONFIG_VIDEO_BT848),y)
-L_I2C=y
 L_TUNERS=y
 else
   ifeq ($(CONFIG_VIDEO_BT848),m)
-    L_I2C=m
     L_TUNERS=m
   endif
 endif
diff -u --recursive --new-file v2.3.49/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h
--- v2.3.49/linux/drivers/char/agp/agp.h	Sat Feb 12 11:22:10 2000
+++ linux/drivers/char/agp/agp.h	Tue Mar  7 11:13:24 2000
@@ -226,6 +226,7 @@
 #define AMD_MMBASE      0x14
 #define AMD_APSIZE      0xac
 #define AMD_MODECNTL    0xb0
+#define AMD_MODECNTL2   0xb2
 #define AMD_GARTENABLE  0x02	/* In mmio region (16-bit register) */
 #define AMD_ATTBASE     0x04	/* In mmio region (32-bit register) */
 #define AMD_TLBFLUSH    0x0c	/* In mmio region (32-bit register) */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- v2.3.49/linux/drivers/char/agp/agpgart_be.c	Sat Feb 26 22:31:44 2000
+++ linux/drivers/char/agp/agpgart_be.c	Tue Mar  7 11:13:24 2000
@@ -1449,6 +1449,9 @@
 
 	/* Write the Sync register */
 	pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80);
+   
+   	/* Set indexing mode */
+   	pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02);
 
 	/* Write the enable register */
 	enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
diff -u --recursive --new-file v2.3.49/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.49/linux/drivers/char/bttv.c	Thu Feb 10 17:11:07 2000
+++ linux/drivers/char/bttv.c	Mon Mar  6 15:32:30 2000
@@ -3,7 +3,7 @@
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.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
@@ -20,6 +20,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <linux/config.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -40,27 +42,28 @@
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
-
+#ifdef LOCK_I2C_BUS
+# error INSTALL ERROR
+# error gcc uses the old, obsolete i2c.h include file.  Please install the \
+	new i2c stack.  Please install it by patching the kernel, otherwise \
+	gcc will not find the new header files.
+#endif
 
 #include "bttv.h"
 #include "tuner.h"
 
 #define DEBUG(x) 		/* Debug driver */
-#define IDEBUG(x) 		/* Debug interrupt handler */
+#define IDEBUG(x)		/* Debug interrupt handler */
 #define MIN(a,b) (((a)>(b))?(b):(a))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
 
 /* Anybody who uses more than four? */
 #define BTTV_MAX 4
-static void bt848_set_risc_jmps(struct bttv *btv);
+static void bt848_set_risc_jmps(struct bttv *btv, int state);
 
 static int bttv_num;			/* number of Bt848s in use */
 static struct bttv bttvs[BTTV_MAX];
@@ -74,7 +77,20 @@
 MODULE_PARM(pll,"1-4i");
 MODULE_PARM(bigendian,"i");
 MODULE_PARM(fieldnr,"i");
+MODULE_PARM(verbose,"i");
+MODULE_PARM(debug,"i");
 MODULE_PARM(autoload,"i");
+MODULE_PARM(gbuffers,"i");
+MODULE_PARM(gbufsize,"i");
+
+EXPORT_SYMBOL(bttv_get_id);
+EXPORT_SYMBOL(bttv_gpio_enable);
+EXPORT_SYMBOL(bttv_read_gpio);
+EXPORT_SYMBOL(bttv_write_gpio);
+EXPORT_SYMBOL(bttv_get_gpio_queue);
+
+MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
+MODULE_AUTHOR("Ralph  Metzler & Marcus Metzler & Gerd Knorr");
 
 #if defined(__sparc__) || defined(__powerpc__)
 static unsigned int bigendian=1;
@@ -87,7 +103,15 @@
 static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 };
 static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0};
 static unsigned int fieldnr = 0;
+static unsigned int verbose = 1;
+static unsigned int debug = 0;
+static unsigned int gbuffers = 2;
+static unsigned int gbufsize = BTTV_MAX_FBUF;
+#ifdef MODULE
 static unsigned int autoload = 1;
+#else
+static unsigned int autoload = 0;
+#endif
 
 
 #define I2C_TIMING (0x7<<4)
@@ -100,6 +124,101 @@
 #define BURSTOFFSET 76
 
 
+/* ----------------------------------------------------------------------- */
+/* Exported functions - for other modules which want to access the         */
+/*                      gpio ports (IR for example)                        */
+/*                      see bttv.h for comments                            */
+
+int bttv_get_id(unsigned int card)
+{
+	if (card >= bttv_num) {
+		return -1;
+	}
+		
+	return bttvs[card].type;
+}
+
+int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+	
+	btv = &bttvs[card];
+	down(&btv->lock);
+	btaor(data, ~mask, BT848_GPIO_OUT_EN);
+	up(&btv->lock);
+
+	return 0;
+}
+
+int bttv_read_gpio(unsigned int card, unsigned long *data)
+{
+	struct bttv *btv;
+	
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = &bttvs[card];
+
+	if(btv->shutdown) {
+		return -ENODEV;
+	}
+
+	down(&btv->lock);
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed 
+   because we set direct input on init */
+
+	*data = btread(BT848_GPIO_DATA);
+
+	up(&btv->lock);
+
+	return 0;
+}
+
+int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
+{
+	struct bttv *btv;
+	
+	if (card >= bttv_num) {
+		return -EINVAL;
+	}
+
+	btv = &bttvs[card];
+
+	down(&btv->lock);
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed 
+   because direct input is set on init */
+
+	btaor(data & mask, ~mask, BT848_GPIO_DATA);
+
+	up(&btv->lock);
+
+	return 0;
+}
+
+WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card)
+{
+	struct bttv *btv;
+
+	if (card >= bttv_num) {
+		return NULL;
+	}
+
+	btv = &bttvs[card];
+
+	if (bttvs[card].shutdown) {
+		return NULL;
+	}
+
+	return &btv->gpioq;
+}
+
 /*******************************/
 /* Memory management functions */
 /*******************************/
@@ -176,11 +295,11 @@
         return ret;
 }
 
-static void * rvmalloc(unsigned long size)
+static void * rvmalloc(signed long size)
 {
 	void * mem;
 	unsigned long adr, page;
-        
+
 	mem=vmalloc(size);
 	if (mem) 
 	{
@@ -197,7 +316,7 @@
 	return mem;
 }
 
-static void rvfree(void * mem, unsigned long size)
+static void rvfree(void * mem, signed long size)
 {
         unsigned long adr, page;
         
@@ -227,7 +346,7 @@
 static int fbuffer_alloc(struct bttv *btv)
 {
 	if(!btv->fbuffer)
-		btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF);
+		btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);
 	else
 		printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
 			btv->nr);
@@ -320,7 +439,8 @@
 	}
 	if (btv->tuner_type != -1)
 		call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
-        printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name);
+        if (verbose)
+		printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name);
         return 0;
 }
 
@@ -328,8 +448,9 @@
 {
         struct bttv *btv = (struct bttv*)client->adapter->data;
 	int i;
-        
-        printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
+
+        if (verbose)
+		printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
 		if (NULL != btv->i2c_clients[i] &&
 		    btv->i2c_clients[i]->driver->id == client->driver->id) {
@@ -395,19 +516,20 @@
 {
         unsigned char buffer = 0;
 
-	if (NULL != probe_for)
+	if (verbose && NULL != probe_for)
 		printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
 		       btv->nr,probe_for,addr);
         btv->i2c_client.addr = addr >> 1;
         if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
-		if (NULL != probe_for)
-			printk("not found\n");
-		else
+		if (NULL != probe_for) {
+			if (verbose)
+				printk("not found\n");
+		} else
 			printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
 			       btv->nr,addr);
                 return -1;
 	}
-	if (NULL != probe_for)
+	if (verbose && NULL != probe_for)
 		printk("found\n");
         return buffer;
 }
@@ -481,31 +603,70 @@
         { TUNER_PHILIPS_PAL,   "Philips FM1216" },
         { TUNER_ABSENT,        "Philips FM1216MF" },
         { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
+        { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
+        { TUNER_ABSENT,        "Philips FM1256" },
+        { TUNER_TEMIC_4036FY5_NTSC,  "Temic 4036FY5" },
+        { TUNER_ABSENT,        "Samsung TCPN9082D" },
+        { TUNER_ABSENT,        "Samsung TCPM9092P" },
+        { TUNER_TEMIC_PAL,     "Temic 4006FH5" },
+        { TUNER_ABSENT,        "Samsung TCPN9085D" },
+        { TUNER_ABSENT,        "Samsung TCPB9085P" },
+        { TUNER_ABSENT,        "Samsung TCPL9091P" },
+        { TUNER_ABSENT,        "Temic 4039FR5" },
+        { TUNER_ABSENT,        "Philips FQ1216 ME" },
+        { TUNER_TEMIC_PAL_I,   "Temic 4066FY5" },
+        { TUNER_ABSENT,        "Philips TD1536" },
+        { TUNER_ABSENT,        "Philips TD1536D" },
+        { TUNER_ABSENT,        "Philips FMR1236" },
+        { TUNER_ABSENT,        "Philips FI1256MP" },
+        { TUNER_ABSENT,        "Samsung TCPQ9091P" },
+        { TUNER_ABSENT,        "Temic 4006FN5" },
+        { TUNER_ABSENT,        "Temic 4009FR5" },
+        { TUNER_ABSENT,        "Temic 4046FM5" },
 };
 
 static void
 hauppauge_eeprom(struct bttv *btv)
 {
-        readee(btv, eeprom_data, 0xa0);
         if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) 
         {
                 btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
-                printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
-                       hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
+		if (verbose)
+			printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
+			       hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
         }
 }
 
 static void
-hauppauge_msp_reset(struct bttv *btv)
+hauppauge_boot_msp34xx(struct bttv *btv)
 {
-        /* Reset the MSP on some Hauppauge cards */
+	int i;
+
+        /* reset/enable the MSP on some Hauppauge cards */
         /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
-        /* Can this hurt cards without one? What about Miros with MSP? */
         btaor(32, ~32, BT848_GPIO_OUT_EN);
         btaor(0, ~32, BT848_GPIO_DATA);
         udelay(2500);
         btaor(32, ~32, BT848_GPIO_DATA);
-        /* btaor(0, ~32, BT848_GPIO_OUT_EN); */
+
+	if (verbose)
+		printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr);
+
+	/* look if the msp3400 driver is already registered */
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (btv->i2c_clients[i] != NULL &&
+		    btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) {
+			return;
+		}
+	}
+
+	/* if not: look for the chip ... */
+	if (I2CRead(btv, I2C_MSP3400, "MSP34xx")) {
+		/* ... if found re-register to trigger a i2c bus rescan, */
+		/*     this time with the msp34xx chip activated */
+		i2c_bit_del_bus(&btv->i2c_adap);
+		i2c_bit_add_bus(&btv->i2c_adap);
+	}
 }
 
 
@@ -528,7 +689,15 @@
 	/* GPIO inputs are pulled up, so no need to drive 
 	 * reset pin any longer */
 	btwrite(0,BT848_GPIO_OUT_EN);
-	
+
+	/*  we could/should try and reset/control the AD pots? but
+	    right now  we simply  turned off the crushing.  Without
+	    this the AGC drifts drifts
+	    remember the EN is reverse logic -->
+	    setting BT848_ADC_AGC_EN disable the AGC
+	    tboult@eecs.lehigh.edu
+	*/
+	btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
 	
 	/*	Initialise MAX517 DAC */
 	printk(KERN_INFO "Setting DAC reference voltage level ...\n");
@@ -555,19 +724,34 @@
 	int id;
 	char *name;
 } vendors[] = {
-	{ 0x0070, "Hauppauge" },
-	{ 0x144f, "Askey" },
+	{ 0x0001, "ATI Technologies Inc" },
+	{ 0x10b4, "STB Systems Inc" },
+	{ 0x13eb, "Hauppauge Computer Works Inc" },
+	{ 0x1461, "Avermedia" },
+	{ 0x1850, "Chronos" },
+	{ 0x1852, "Typhoon" },
+	{ 0x3000, "Askey" },
+	{ 0x3002, "Askey" },
+	{ 0x6606, "Leadtek" },
 	{ -1, NULL }
 };
 
 static struct CARD {
-	int id;
 	int vid;
+	int id;
 	int cardnr;
 	char *name;
 } cards[] = {
-	{ 0x13eb, 0x0070, BTTV_HAUPPAUGE878,  "WinTV Theater" },
-	{ 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView"   },
+	{ 0x0001, 0x1002, BTTV_HAUPPAUGE878,  "TV Wonder" },
+	{ 0x10b4, 0x2636, BTTV_HAUPPAUGE878,  "???" },
+	{ 0x13eb, 0x0070, BTTV_HAUPPAUGE878,  "WinTV" },
+	{ 0x1461, 0x0002, BTTV_AVERMEDIA98,   "TVCapture 98" },
+	{ 0x1850, 0x1851, BTTV_CHRONOS_VS2,   "Video Shuttle II" },
+	{ 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" },
+	{ 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99"  },
+	{ 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView"  },
+	{ 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS,  "TV Master"  },
+	{ 0x6606, 0x217d, BTTV_WINFAST2000,   "WinFast TV 2000" },
 	{ -1, -1, -1, NULL }
 };
 
@@ -594,7 +778,7 @@
 static struct tvcard tvcards[] = 
 {
 	/* 0x00 */
-        { "unknown",
+        { " *** UNKNOWN *** ",
           3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
 	  1,1,1,1,0 },
         { "MIRO PCTV",
@@ -614,7 +798,7 @@
           3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0,
 	  1,1,1,1,0 },
 	{ "AVerMedia TVPhone",
-          3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0,
+          3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0,
 	  1,1,1,1,0 },
         { "MATRIX-Vision MV-Delta",
           5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
@@ -713,16 +897,32 @@
 	{ "Terratec TerraTValue",
           3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
 	  1,1,1,1,0 },
+	{ "Leadtek WinFast 2000",
+	  3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0},
+	  { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0,
+	  1,1,1,1,1 },
+	{ "Chronos Video Shuttle II",
+	  3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0,
+	  1,1,1,1,0 },
+
+	{ "Typhoon TView TV/FM Tuner",
+	  3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0,
+	  1,1,1,1,0 },
+	{ "PixelView PlayTV pro",                                                               
+          3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },                                                     
+          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 }
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
 static void
-dump_eeprom(struct bttv *btv, int addr)
+dump_eeprom(struct bttv *btv,int addr)
 {
-	int i,id1,id2,n1,n2;
+	int i;
 
+	if (verbose < 2)
+		return;
+	/* for debugging: dump eeprom to syslog */
 	printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr);
-        readee(btv, eeprom_data,addr);
 	for (i = 0; i < 256;) {
 		printk(KERN_DEBUG "  %02x:",i);
 		do {
@@ -730,35 +930,47 @@
 		} while (i % 16);
 		printk("\n");
 	}
-	id1 = (eeprom_data[252] << 8) | (eeprom_data[253]);
-	id2 = (eeprom_data[254] << 8) | (eeprom_data[255]);
-	if (id1 != 0 && id1 != 0xffff &&
-	    id2 != 0 && id2 != 0xffff) {
-		n1 = -1;
-		n2 = -1;
-		for (i = 0; vendors[i].id != -1; i++)
-			if (vendors[i].id == id2)
-				n2 = i;
-		for (i = 0; cards[i].id != -1; i++)
-			if (cards[i].id  == id1 &&
-			    cards[i].vid == id2)
-				n1 = i;
-		if (n1 != -1 && n2 != -1) {
-			printk(KERN_INFO "  id: %s (0x%04x), vendor: %s (0x%04x)\n",
-			       cards[n1].name,id1,vendors[n2].name,id2);
-			printk(KERN_INFO "  => card=%d (%s)\n",
-			       cards[n1].cardnr,tvcards[cards[n1].cardnr].name);
-#if 1
-			/* not yet, but that's the plan for autodetect... */
-			btv->type = cards[n1].cardnr;
-#endif
-		} else {
-			printk(KERN_INFO "  id: %s (0x%04x), vendor: %s (0x%04x)\n",
-			       (n1 != -1) ? cards[n1].name   : "unknown", id1,
-			       (n2 != -1) ? vendors[n2].name : "unknown", id2);
-			printk(KERN_INFO "  please mail card type, id + vendor to ");
-			printk(" kraxel@goldbach.in-berlin.de\n");
-		}
+}
+
+static int
+idcard_eeprom(struct bttv *btv)
+{
+	int i,id1,id2,n1,n2;
+
+	id1 = (eeprom_data[254] << 8) | (eeprom_data[255]);
+	id2 = (eeprom_data[252] << 8) | (eeprom_data[253]);
+	if (id1 == 0 || id1 == 0xffff ||
+	    id2 == 0 || id2 == 0xffff)
+		return -1;
+
+	/* look for the card */
+	n1 = -1; n2 = -1;
+	for (i = 0; vendors[i].id != -1; i++)
+		if (vendors[i].id == id2)
+			n2 = i;
+	for (i = 0; cards[i].id != -1; i++)
+		if (cards[i].id  == id1 &&
+		    cards[i].vid == id2)
+			n1 = i;
+
+	if (n1 != -1 && n2 != -1) {
+		/* found it */
+		printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
+		       btv->nr,cards[n1].name,id1,vendors[n2].name,id2);
+		if (verbose)
+			printk(KERN_INFO "bttv%d:   => card=%d (%s)\n",
+			       btv->nr,cards[n1].cardnr,
+			       tvcards[cards[n1].cardnr].name);
+		return cards[n1].cardnr;
+	} else {
+		/* 404 */
+		printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
+		       btv->nr, "unknown", id1,
+		       (n2 != -1) ? vendors[n2].name : "unknown", id2);
+		printk(KERN_INFO "please mail id + vendor, board name and "
+		       "the correct card= insmod option to "
+		       "kraxel@goldbach.in-berlin.de\n");
+		return -1;
 	}
 }
 
@@ -810,21 +1022,6 @@
 }
 
 
-static void bt848_cap(struct bttv *btv, uint state)
-{
-	if (state) 
-	{
-		btv->cap|=3;
-		bt848_set_risc_jmps(btv);
-	}
-	else
-	{
-		btv->cap&=~3;
-		bt848_set_risc_jmps(btv);
-	}
-}
-
-
 /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
 
 /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C 
@@ -885,9 +1082,10 @@
                 /* printk("bttv%d: PLL: no change required\n",btv->nr); */
                 return 1;
         }
-        
-        printk("bttv%d: PLL: %d => %d ... ",btv->nr,
-               btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+
+        if (verbose)
+		printk("bttv%d: PLL: %d => %d ... ",btv->nr,
+		       btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
 	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
@@ -907,13 +1105,15 @@
                 {
                         btwrite(0x08,BT848_TGCTRL);
                         btv->pll.pll_current = btv->pll.pll_ofreq;
-                        printk("ok\n");
+			if (verbose)
+				printk("ok\n");
                         return 1;
                 }
                 mdelay(10);
         }
         btv->pll.pll_current = 0;
-        printk("oops\n");
+	if (verbose)
+		printk("oops\n");
         return -1;
 }
 
@@ -1010,10 +1210,9 @@
 	unsigned int *po=(unsigned int *) btv->vbi_odd;
 	unsigned int *pe=(unsigned int *) btv->vbi_even;
   
-	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));
+	if (debug)
+		printk("bttv%d: vbi: po=%08lx pe=%08lx\n",
+		       btv->nr,virt_to_bus(po), virt_to_bus(pe));
         
 	*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
 	for (i=0; i<16; i++) 
@@ -1036,11 +1235,11 @@
 	DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
 }
 
-int fmtbppx2[16] = {
+static int fmtbppx2[16] = {
         8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 
 };
 
-int palette2fmt[] = {
+static int palette2fmt[] = {
        0,
        BT848_COLOR_FMT_Y8,
        BT848_COLOR_FMT_RGB8,
@@ -1082,7 +1281,7 @@
                 *(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));
+                *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2));
                 vadr+=bpl;
 	}
 	
@@ -1108,6 +1307,9 @@
 	unsigned long vadr=(unsigned long) vbuf;
 	int shift, csize;	
 
+	if (debug)
+		printk("bttv%d: prisc: ro=%08lx re=%08lx\n",
+		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
 
 	switch(fmt)
 	{
@@ -1140,7 +1342,7 @@
 	}
 	cbadr=vadr+(width*height);
 	cradr=cbadr+csize;
-	inter = (height>btv->win.cropheight/2) ? 1 : 0;
+	inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
 	
 	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
         *(ro++)=0;
@@ -1158,7 +1360,7 @@
 	        if (inter) 
 		        rp= (line&1) ? &re : &ro;
 		else 
-	                rp= (line>=height) ? &re : &ro; 
+	                rp= (line>=height) ? &ro : &re; 
 	                
 
 	        if(line&lmask)
@@ -1222,9 +1424,12 @@
                 return make_rawrisctab(btv, ro, re, vbuf);
         if (palette>=VIDEO_PALETTE_PLANAR)
                 return make_prisctab(btv, ro, re, vbuf, width, height, palette);
-        
-        
-	inter = (height>btv->win.cropheight/2) ? 1 : 0;
+
+	if (debug)
+		printk("bttv%d: vrisc: ro=%08lx re=%08lx\n",
+		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
+	
+	inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
 	bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
 	
 	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 
@@ -1237,7 +1442,7 @@
 	        if (inter) 
 		        rp= (line&1) ? &re : &ro;
 		else 
-	                rp= (line>=height) ? &re : &ro; 
+	                rp= (line>=height) ? &ro : &re; 
 
 		bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
 		if (bpl<=bl)
@@ -1335,32 +1540,31 @@
 
 static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
 {
-	int i, line, x, y, bpl, width, height, inter;
+	int i, line, x, y, bpl, width, height, inter, maxw;
 	unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len;
 	unsigned long adr;
-	unsigned char *clipmap, cbit, lastbit, outofmem;
+	unsigned char *clipmap, *clipline, cbit, lastbit, outofmem;
 
-	if (btv->win.use_yuv) {
-		/* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */
-		bpp    = 2;
-		bpl    = btv->win.win2.pitch;
-		adr    = btv->win.vidadr + btv->win.win2.start;
-	} else {
-		bpp=btv->win.bpp;
-		if (bpp==15)	/* handle 15bpp as 16bpp in calculations */
-			bpp++;
-		bpl=btv->win.bpl;
-		adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
-	}
+	/* take care: bpp != btv->win.bpp is allowed here */
+	bpp = fmtbppx2[btv->win.color_fmt&0xf]/2;
+	bpl=btv->win.bpl;
+	adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl;
 	inter=(btv->win.interlace&1)^1;
 	width=btv->win.width;
 	height=btv->win.height;
+	if (debug)
+		printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
+		       btv->nr,btv->picture.palette,width,height,bpl,bpp);
 	if(width > 1023)
 		width = 1023;		/* sanity check */
 	if(height > 625)
 		height = 625;		/* sanity check */
-	ro=btv->risc_odd;
-	re=btv->risc_even;
+	ro=btv->risc_scr_odd;
+	re=btv->risc_scr_even;
+
+	if (debug)
+		printk("bttv%d: clip: ro=%08lx re=%08lx\n",
+		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
 
 	if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
 		/* can't clip, don't generate any risc code */
@@ -1380,16 +1584,15 @@
 	/* clip against viewing window AND screen 
 	   so we do not have to rely on the user program
 	 */
-	if (!btv->win.use_yuv) {
-		clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ?
-				    (btv->win.swidth-btv->win.x) : width, 0, 1024, 768);
-		clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ?
-				    (btv->win.sheight-btv->win.y) : height,1024,768);
-		if (btv->win.x<0)
-			clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768);
-		if (btv->win.y<0)
-			clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
-	}
+	maxw = (bpl - btv->win.x * btv->win.bpp) / bpp;
+	clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width,
+			    0, 1024, 768);
+	clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ?
+			    (btv->win.sheight-btv->win.y) : height,1024,768);
+	if (btv->win.x<0)
+		clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768);
+	if (btv->win.y<0)
+		clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
 	
 	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
         *(ro++)=cpu_to_le32(0);
@@ -1401,12 +1604,30 @@
         {
 		y = line>>inter;
 		rp= (line&1) ? &re : &ro;
-		lastbit=(clipmap[y<<7]&1);
-		for(x=dx=1,sx=0; x<=width && !outofmem; x++) {
-			cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7)));
-			if (x < width && !lastbit == !cbit)
+		clipline = clipmap + (y<<7); /* running pointers ... */
+		lastbit = *clipline & 1;
+		for(x=dx=0,sx=0; x<=width && !outofmem;) {
+			if (0 == (x&7)) {
+				/* check bytes not bits if we can ... */
+				if (lastbit) {
+					while (0xff==*clipline && x<width-8) {
+						x  += 8;
+						dx += 8;
+						clipline++;
+					}
+				} else {
+					while (0x00==*clipline && x<width-8) {
+						x  += 8;
+						dx += 8;
+						clipline++;
+					}
+				}
+			}
+			cbit = *clipline & (1<<(x&7));
+			if (x < width && !lastbit == !cbit) {
 				dx++;
-			else {	/* generate the dma controller code */
+			} else {
+				/* generate the dma controller code */
 				len = dx * bpp;
 				flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
 				flags |= ((!sx) ? BT848_RISC_SOL : 0);
@@ -1420,11 +1641,14 @@
 				lastbit=cbit;
 				sx += dx;
 				dx = 1;
-				if (ro - btv->risc_odd > RISCMEM_LEN/2 - 16)
+				if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16)
 					outofmem++;
-				if (re - btv->risc_even > RISCMEM_LEN/2 - 16)
+				if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16)
 					outofmem++;
 			}
+			x++;
+			if (0 == (x&7))
+				clipline++;
 		}
 		if ((!inter)||(line&1))
                         adr+=bpl;
@@ -1475,29 +1699,25 @@
 }
 
 
-static void bt848_set_geo(struct bttv *btv, u16 width, u16 height,
-			  u16 fmt, int no_irq_context)
+static void bt848_set_geo(struct bttv *btv,
+			  int no_irq_context)
 {
         u16 vscale, hscale;
 	u32 xsf, sr;
-	u16 hdelay, vdelay;
-	u16 hactive, vactive;
+	u16 ewidth, eheight, owidth, oheight;
+	u16 format, bswap;
+	u16 hdelay;
+	u16 hactive;
 	u16 inter;
 	u8 crop, vtc;  
 	struct tvnorm *tvn;
 	unsigned long flags;
  	
-	if (!width || !height)
-	        return;
-
 	save_flags(flags);
 	cli();
 
 	tvn=&tvnorms[btv->win.norm];
 	
-        btv->win.cropheight=tvn->sheight;
-        btv->win.cropwidth=tvn->swidth;
-
 	btwrite(tvn->adelay, BT848_ADELAY);
 	btwrite(tvn->bdelay, BT848_BDELAY);
 	btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
@@ -1508,59 +1728,84 @@
 	if (no_irq_context)
 		set_pll(btv);
 
-	btwrite(fmt, BT848_COLOR_FMT);
-	if (bigendian &&
-	    fmt == BT848_COLOR_FMT_RGB32) {
-                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 (bigendian &&
-		   (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);
-        } else {
-		btwrite(0x10, BT848_COLOR_CTL);
-	}
-	hactive=width;
-
         vtc=0;
 	/* Some people say interpolation looks bad ... */
 	/* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
      
-	btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
-	inter=(btv->win.interlace&1)^1;
-	vdelay=btv->win.cropy+tvn->vdelay;
+	btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0;
 
-	xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
-	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
-
-	hdelay=tvn->hdelayx1+btv->win.cropx;
-	hdelay=(hdelay*hactive)/btv->win.cropwidth;
-	hdelay&=0x3fe;
+	if (0 == btv->risc_cap_odd &&
+	    0 == btv->risc_cap_even) {
+		/* overlay only */
+		owidth  = btv->win.width;
+		oheight = btv->win.height;
+		ewidth  = btv->win.width;
+		eheight = btv->win.height;
+		format  = btv->win.color_fmt;
+		bswap   = btv->fb_color_ctl;
+	} else if (-1 != btv->gq_grab      &&
+		   0  == btv->risc_cap_odd &&
+		   !btv->win.interlace     &&
+		   btv->scr_on) {
+		/* odd field -> overlay, even field -> capture */
+		owidth  = btv->win.width;
+		oheight = btv->win.height;
+		ewidth  = btv->gbuf[btv->gq_grab].width;
+		eheight = btv->gbuf[btv->gq_grab].height;
+		format  = (btv->win.color_fmt & 0xf0) |
+			(btv->gbuf[btv->gq_grab].fmt & 0x0f);
+		bswap   = btv->fb_color_ctl & 0x0a;
+	} else {
+		/* capture only */
+		owidth  = btv->gbuf[btv->gq_grab].width;
+		oheight = btv->gbuf[btv->gq_grab].height;
+		ewidth  = btv->gbuf[btv->gq_grab].width;
+		eheight = btv->gbuf[btv->gq_grab].height;
+		format  = btv->gbuf[btv->gq_grab].fmt;
+		bswap   = 0;
+		inter   = (btv->win.height>tvn->sheight/2) ? 0 : 1;
+	}
 
-	sr=((btv->win.cropheight>>inter)*512)/height-512;
+	inter = (oheight>tvn->sheight/2) ? 0 : 1;
+
+	/* odd field */
+	hactive=owidth;
+	xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
+	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	hdelay =  tvn->hdelayx1;
+	hdelay =  (hdelay*hactive)/tvn->swidth;
+	hdelay &= 0x3fe;
+	sr=((tvn->sheight>>inter)*512)/oheight-512;
 	vscale=(0x10000UL-sr)&0x1fff;
-	vactive=btv->win.cropheight;
 	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
-	        ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
-	vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
+	vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+	bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight,
+			hdelay, tvn->vdelay, crop);
+
+	/* even field */
+	hactive=ewidth;
+	xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
+	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	hdelay =  tvn->hdelayx1;
+	hdelay =  (hdelay*hactive)/tvn->swidth;
+	hdelay &= 0x3fe;
+	sr=((tvn->sheight>>inter)*512)/eheight-512;
+	vscale=(0x10000UL-sr)&0x1fff;
+	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
+		((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
+	vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+	bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight,
+			hdelay, tvn->vdelay, crop);
 
-	bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive,
-			hdelay, vdelay, crop);
-	bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
-			hdelay, vdelay, crop);
+	btwrite(format, BT848_COLOR_FMT);
+	btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
 
 	restore_flags(flags);
 }
 
 
-int bpp2fmt[4] = {
+static int bpp2fmt[4] = {
         BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
         BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 
 };
@@ -1569,14 +1814,31 @@
 {
         unsigned short format;
 
-	if (btv->win.use_yuv) {
-		/* yuv-to-offscreen */
-		format = BT848_COLOR_FMT_YUY2;
+	if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) {
+		/* format set by VIDIOCSPICT */
+		format = palette2fmt[btv->picture.palette];
 	} else {
+		/* use default for the given color depth */
 		format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
 			bpp2fmt[(btv->win.bpp-1)&3];
 	}
 	btv->win.color_fmt = format;
+	if (bigendian &&
+	    format == BT848_COLOR_FMT_RGB32) {
+		btv->fb_color_ctl =
+			BT848_COLOR_CTL_WSWAP_ODD	|
+			BT848_COLOR_CTL_WSWAP_EVEN	|
+			BT848_COLOR_CTL_BSWAP_ODD	|
+			BT848_COLOR_CTL_BSWAP_EVEN;
+        } else if (bigendian &&
+		   (format == BT848_COLOR_FMT_RGB16 ||
+                    format == BT848_COLOR_FMT_RGB15)) {
+		btv->fb_color_ctl =
+			BT848_COLOR_CTL_BSWAP_ODD	|
+			BT848_COLOR_CTL_BSWAP_EVEN;
+        } else {
+		btv->fb_color_ctl = 0;
+	}
 
 	/*	RGB8 seems to be a 9x5x5 GRB color cube starting at
 	 *	color 16. Why the h... can't they even mention this in the
@@ -1590,38 +1852,8 @@
 	else
 	        btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
 
-        bt848_set_geo(btv, btv->win.width, btv->win.height, format,1);
-}
-
-/*
- *	Set TSA5522 synthesizer frequency in 1/16 Mhz steps
- */
-
-#if 0
-static void set_freq(struct bttv *btv, unsigned short freq)
-{
-	int naudio;
-	int fixme = freq; /* XXX */
-	/* int oldAudio = btv->audio; */
-
-        /* mute */
-        AUDIO(AUDC_SWITCH_MUTE,0);
-
-	/* tune */
-	if (btv->radio) {
-		TUNER(TUNER_SET_RADIOFREQ,&fixme);
-	} else {
-		TUNER(TUNER_SET_TVFREQ,&fixme);
-        }
-	
-	if (btv->radio) {
-		AUDIO(AUDC_SET_RADIO,0);
-	} else {
-		AUDIO(AUDC_SET_TVNORM,&(btv->win.norm));
-		AUDIO(AUDC_NEWCHANNEL,0);
-        }
+        bt848_set_geo(btv,1);
 }
-#endif
 
 
 /*
@@ -1639,30 +1871,19 @@
 		if(fbuffer_alloc(btv))
 			return -ENOBUFS;
 	}
-	if(btv->grabbing >= MAX_GBUFFERS)
-		return -ENOBUFS;
-	
-	/*
-	 *	No grabbing past the end of the buffer!
-	 */
-	 
-	if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0)
+
+	if(mp->frame >= gbuffers || mp->frame < 0)
 		return -EINVAL;
+	if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED)
+		return -EBUSY;
 		
 	if(mp->height <0 || mp->width <0)
 		return -EINVAL;
-	
-/*      This doesn´t work like this for NTSC anyway.
-        So, better check the total image size ...
-*/
-/*
-	if(mp->height>576 || mp->width>768+BURSTOFFSET)
-		return -EINVAL;
-*/
 	if (mp->format >= PALETTEFMT_MAX)
 		return -EINVAL;
+
 	if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2
-	    > BTTV_MAX_FBUF)
+	    > gbufsize)
 		return -EINVAL;
 	if(-1 == palette2fmt[mp->format])
 		return -EINVAL;
@@ -1677,41 +1898,40 @@
 	 *	Ok load up the BT848
 	 */
 	 
-	vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
-/*	if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
-                return -EAGAIN;*/
-	ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
+	vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame);
+	ro=btv->gbuf[mp->frame].risc;
 	re=ro+2048;
         make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
-	/* bt848_set_risc_jmps(btv); */
+
+	if (debug)
+		printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame);
         cli();
-        btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
-        if (btv->grabbing) {
-		btv->gfmt_next=palette2fmt[mp->format];
-		btv->gwidth_next=mp->width;
-		btv->gheight_next=mp->height;
-		btv->gro_next=virt_to_bus(ro);
-		btv->gre_next=virt_to_bus(re);
-                btv->grf_next=mp->frame;
-        } else {
-		btv->gfmt=palette2fmt[mp->format];
-		btv->gwidth=mp->width;
-		btv->gheight=mp->height;
-		btv->gro=virt_to_bus(ro);
-		btv->gre=virt_to_bus(re);
-                btv->grf=mp->frame;
-        }
-	if (!(btv->grabbing++)) {
+        btv->gbuf[mp->frame].stat    = GBUFFER_GRABBING;
+	btv->gbuf[mp->frame].fmt     = palette2fmt[mp->format];
+	btv->gbuf[mp->frame].width   = mp->width;
+	btv->gbuf[mp->frame].height  = mp->height;
+	btv->gbuf[mp->frame].ro      = virt_to_bus(ro);
+	btv->gbuf[mp->frame].re      = virt_to_bus(re);
+
+#if 1
+	if (mp->height <= tvnorms[btv->win.norm].sheight/2 &&
+	    mp->format != VIDEO_PALETTE_RAW)
+		btv->gbuf[mp->frame].ro = 0;
+#endif
+
+	if (btv->gq_in == btv->gq_out) {
 		if(mp->format>=VIDEO_PALETTE_COMPONENT) {
 			btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
 			btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
 		}
 		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
+	btv->gqueue[btv->gq_in++] = mp->frame;
+	btv->gq_in = btv->gq_in % MAX_GBUFFERS;
+
         sti();
 	btor(3, BT848_CAP_CTL);
 	btor(3, BT848_GPIO_DMA_CTL);
-	/* interruptible_sleep_on(&btv->capq); */
 	return 0;
 }
 
@@ -1787,16 +2007,16 @@
 	if (btv->user)
 		goto out_unlock;
 	
-	btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF);
+	btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);
 	ret = -ENOMEM;
 	if (!btv->fbuffer)
 		goto out_unlock;
 
-        btv->grabbing = 0;
-        btv->grab = 0;
-        btv->lastgrab = 0;
-        for (i = 0; i < MAX_GBUFFERS; i++)
-                btv->frame_stat[i] = GBUFFER_UNUSED;
+        btv->gq_in = 0;
+        btv->gq_out = 0;
+	btv->gq_grab = -1;
+        for (i = 0; i < gbuffers; i++)
+                btv->gbuf[i].stat = GBUFFER_UNUSED;
 
         burst(0);
         btv->user++;
@@ -1815,8 +2035,10 @@
 
 	down(&btv->lock);
 	btv->user--;
-	btv->cap&=~3;
-	bt848_set_risc_jmps(btv);
+	btv->scr_on = 0;
+	btv->risc_cap_odd = 0;
+	btv->risc_cap_even = 0;
+	bt848_set_risc_jmps(btv,-1);
 
 	/*
 	 *	A word of warning. At this point the chip
@@ -1841,7 +2063,7 @@
 	 */
 
 	if(btv->fbuffer)
-		rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF);
+		rvfree((void *) btv->fbuffer, gbuffers*gbufsize);
 	btv->fbuffer=0;
 	up(&btv->lock);
 	MOD_DEC_USE_COUNT;  
@@ -1901,7 +2123,9 @@
 static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
 	struct bttv *btv=(struct bttv *)dev;
- 	int i;
+ 	int i,ret;
+
+	if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
 
 	switch (cmd) {
 	case VIDIOCGCAP:
@@ -2021,17 +2245,6 @@
 	case VIDIOCGPICT:
 	{
 		struct video_picture p=btv->picture;
-		if(btv->win.depth==8)
-			p.palette=VIDEO_PALETTE_HI240;
-		if(btv->win.depth==15)
-			p.palette=VIDEO_PALETTE_RGB555;
-		if(btv->win.depth==16)
-			p.palette=VIDEO_PALETTE_RGB565;
-		if(btv->win.depth==24)
-			p.palette=VIDEO_PALETTE_RGB24;
-		if(btv->win.depth==32)
-			p.palette=VIDEO_PALETTE_RGB32;
-			
 		if(copy_to_user(arg, &p, sizeof(p)))
 			return -EFAULT;
 		return 0;
@@ -2041,6 +2254,8 @@
 		struct video_picture p;
 		if(copy_from_user(&p, arg,sizeof(p)))
 			return -EFAULT;
+		if (p.palette > PALETTEFMT_MAX)
+			return -EINVAL;
 		down(&btv->lock);
 		/* We want -128 to 127 we get 0-65535 */
 		bt848_bright(btv, (p.brightness>>8)-128);
@@ -2059,7 +2274,6 @@
 	{
 		struct video_window vw;
 		struct video_clip *vcp = NULL;
-		int on;
 			
 		if(copy_from_user(&vw,arg,sizeof(vw)))
 			return -EFAULT;
@@ -2067,25 +2281,24 @@
 		if(vw.flags || vw.width < 16 || vw.height < 16) 
 		{
                         down(&btv->lock);
-			bt848_cap(btv,0);
+			btv->scr_on = 0;
+			bt848_set_risc_jmps(btv,-1);
 			up(&btv->lock);
 			return -EINVAL;
-		}		
+		}
 		if (btv->win.bpp < 4) 
 		{	/* adjust and align writes */
 			vw.x = (vw.x + 3) & ~3;
 			vw.width &= ~3;
 		}
 		down(&btv->lock);
-		btv->win.use_yuv=0;
 		btv->win.x=vw.x;
 		btv->win.y=vw.y;
 		btv->win.width=vw.width;
 		btv->win.height=vw.height;
 
-		on=(btv->cap&3);
-			
-		bt848_cap(btv,0);
+		bt848_set_risc_jmps(btv,0);
+		
 		bt848_set_winsize(btv);
 		up(&btv->lock);
 
@@ -2115,39 +2328,7 @@
 		make_clip_tab(btv, vcp, vw.clipcount);
 		if (vw.clipcount != 0)
 			vfree(vcp);
-		if(on && btv->win.vidadr!=0)
-			bt848_cap(btv,1);
-		up(&btv->lock);
-		return 0;
-	}
-	case VIDIOCSWIN2:
-	{
-		/* experimental -- right now it handles unclipped yuv data only */
-		struct video_window2 vo;
-		__u32 fbsize;
-		int on;
-			
-		if(copy_from_user(&vo,arg,sizeof(vo)))
-			return -EFAULT;
-
-		fbsize = btv->win.sheight * btv->win.bpl;
-		if (vo.start + vo.pitch*vo.height > fbsize)
-			return -EINVAL;
-                if (vo.palette != VIDEO_PALETTE_YUV422)
-			return -EINVAL;
-		
-		down(&btv->lock);
-		btv->win.use_yuv=1;
-		memcpy(&btv->win.win2,&vo,sizeof(vo));
-		btv->win.width=vo.width;
-		btv->win.height=vo.height;
-
-		on=(btv->cap&3);
-		bt848_cap(btv,0);
-		bt848_set_winsize(btv);
-		make_clip_tab(btv, NULL, 0);
-		if(on && btv->win.vidadr!=0)
-			bt848_cap(btv,1);
+		bt848_set_risc_jmps(btv,-1);
 		up(&btv->lock);
 		return 0;
 	}
@@ -2174,13 +2355,14 @@
 			return -EFAULT;
 		if(btv->win.vidadr == 0)
 			return -EINVAL;
-		if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0))
+		if (btv->win.width==0 || btv->win.height==0)
 			return -EINVAL;
 		down(&btv->lock);
-		if(v==0)
-			bt848_cap(btv,0);
-		else
-			bt848_cap(btv,1);
+		if (v == 1 && btv->win.vidadr != 0)
+			btv->scr_on = 1;
+		if (v == 0)
+			btv->scr_on = 0;
+		bt848_set_risc_jmps(btv,-1);
 		up(&btv->lock);
 		return 0;
 	}
@@ -2217,9 +2399,19 @@
 		btv->win.bpp=((v.depth+7)&0x38)/8;
 		btv->win.depth=v.depth;
 		btv->win.bpl=v.bytesperline;
-			
-		DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
-			     v.base, v.width,v.height, btv->win.bpp, btv->win.bpl));
+
+		/* set sefault color format */
+		switch (btv->win.bpp) {
+		case  8: btv->picture.palette = VIDEO_PALETTE_HI240;  break;
+		case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break;
+		case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break;
+		case 24: btv->picture.palette = VIDEO_PALETTE_RGB24;  break;
+		case 32: btv->picture.palette = VIDEO_PALETTE_RGB32;  break;
+		}
+	
+		if (debug)
+			printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
+			       v.base, v.width,v.height, btv->win.bpp, btv->win.bpl);
 		bt848_set_winsize(btv);
 		up(&btv->lock);
 		return 0;		
@@ -2273,19 +2465,6 @@
 			v.step = 4096;
 		}
 
-#if 0
-#warning this should be handled by tda9855.c
-		else if (btv->audio_chip == TDA9850) {
-			unsigned char ALR1;
-			v.flags|=VIDEO_AUDIO_VOLUME;
-			ALR1 = I2CRead(btv, I2C_TDA9850|1);
-			v.mode = VIDEO_SOUND_MONO;
-			v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0;
-			v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0;
-			v.volume = 32768;       /* fixme */
-			v.step = 4096;
-		}
-#endif
 		if(copy_to_user(arg,&v,sizeof(v)))
 			return -EFAULT;
 		return 0;
@@ -2354,23 +2533,8 @@
 			udelay(10);                     
 			data &= ~WINVIEW_PT2254_STROBE;
 			btwrite(data, BT848_GPIO_DATA);
-
-#if 0
-#warning this should be handled by tda9855.c
-		} else if (btv->audio_chip == TDA9850) {
-			unsigned char con3 = 0;
-			if (v.mode & VIDEO_SOUND_LANG1)
-				con3 = 0x80;	/* sap */
-			if (v.mode & VIDEO_SOUND_STEREO)
-				con3 = 0x40;	/* stereo */
-			I2CWrite(btv, I2C_TDA9850,
-				 TDA9850_CON3, con3, 1);
-			if (v.flags & VIDEO_AUDIO_VOLUME)
-				I2CWrite(btv, I2C_TDA9850,
-					 TDA9850_CON4,
-					 (v.volume>>12) & 15, 1);
-#endif
 		}
+
 		btv->audio_dev=v;
 		up(&btv->lock);
 		return 0;
@@ -2379,19 +2543,27 @@
 	case VIDIOCSYNC:
 		if(copy_from_user((void *)&i,arg,sizeof(int)))
 			return -EFAULT;
-		switch (btv->frame_stat[i]) {
+		if (i < 0 || i >= gbuffers)
+			return -EINVAL;
+		switch (btv->gbuf[i].stat) {
 		case GBUFFER_UNUSED:
 			return -EINVAL;
 		case GBUFFER_GRABBING:
-			while(btv->frame_stat[i]==GBUFFER_GRABBING) {
+			while(btv->gbuf[i].stat==GBUFFER_GRABBING) {
+				if (debug)
+					printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
 				interruptible_sleep_on(&btv->capq);
 				if(signal_pending(current))
 					return -EINTR;
 			}
-                                /* fall */
+			/* fall throuth */
 		case GBUFFER_DONE:
-			btv->frame_stat[i] = GBUFFER_UNUSED;
-			break;
+		case GBUFFER_ERROR:
+			ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0;
+			if (debug)
+				printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret);
+			btv->gbuf[i].stat = GBUFFER_UNUSED;
+			return ret;
 		}
 		return 0;
 
@@ -2422,8 +2594,6 @@
 		int ret;
 		if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
 			return -EFAULT;
-		if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
-			return -EBUSY;
 		down(&btv->lock);
 		ret = vgrab(btv, &vm);
 		up(&btv->lock);
@@ -2434,10 +2604,10 @@
 	{
 		struct video_mbuf vm;
 		memset(&vm, 0 , sizeof(vm));
-		vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS;
-		vm.frames=MAX_GBUFFERS;
-		vm.offsets[0]=0;
-		vm.offsets[1]=BTTV_MAX_FBUF;
+		vm.size=gbufsize*gbuffers;
+		vm.frames=gbuffers;
+		for (i = 0; i < gbuffers; i++)
+			vm.offsets[i]=i*gbufsize;
 		if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
 			return -EFAULT;
 		return 0;
@@ -2510,7 +2680,7 @@
         unsigned long start=(unsigned long) adr;
         unsigned long page,pos;
 
-        if (size>2*BTTV_MAX_FBUF)
+        if (size>gbuffers*gbufsize)
                 return -EINVAL;
         if (!btv->fbuffer) {
                 if(fbuffer_alloc(btv))
@@ -2623,8 +2793,8 @@
 
         down(&btv->lock);
 	btv->vbip=VBIBUF_SIZE;
-	btv->cap|=0x0c;
-	bt848_set_risc_jmps(btv);
+	btv->vbi_on = 1;
+	bt848_set_risc_jmps(btv,-1);
 	up(&btv->lock);
 
 	MOD_INC_USE_COUNT;
@@ -2636,8 +2806,8 @@
 	struct bttv *btv=(struct bttv *)(dev-2);
 
         down(&btv->lock);
-	btv->cap&=~0x0c;
-	bt848_set_risc_jmps(btv);
+	btv->vbi_on = 0;
+	bt848_set_risc_jmps(btv,-1);
 	up(&btv->lock);
 
 	MOD_DEC_USE_COUNT;  
@@ -2875,26 +3045,12 @@
            7a - external */
 }
 
-
-#if 0
-#warning this should be handled by tda9855.c
-static void init_tda9850(struct bttv *btv)
-{
-        I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1);  /* noise threshold st */
-	I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1);  /* noise threshold sap */
-	I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1);  /* stereo mode */
-	I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1);  /* 0 dB input gain?*/
-	I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1);  /* wideband alignment? */
-	I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1);  /* spectral alignment? */
-	I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1);
-}
-#endif
-
 /* Figure out card and tuner type */
 
 static void idcard(int i)
 {
         struct bttv *btv = &bttvs[i];
+	int type,eeprom = 0;
 
 	btwrite(0, BT848_GPIO_OUT_EN);
 	DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA)));
@@ -2903,40 +3059,36 @@
 	if (card[i] >= 0 && card[i] < TVCARDS)
 		btv->type=card[i];
 
-	/* If we were asked to auto-detect, then do so! 
-	   Right now this will only recognize Miro, Hauppauge or STB
-	   */
-	if (btv->type == BTTV_UNKNOWN) 
-	{
-		if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0)
-		{
-			if(btv->id>849)
-				btv->type=BTTV_HAUPPAUGE878;
-			else
+	/* If we were asked to auto-detect, then do so! */
+	if (btv->type == BTTV_UNKNOWN) {
+			
+		/* many bt878 cards have a eeprom @ 0xa0 => read ID
+		   and try to identify it */
+		if (I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) {
+			eeprom = 0xa0;
+			readee(btv,eeprom_data,0xa0);
+			dump_eeprom(btv,0xa0); /* DEBUG */
+			type = idcard_eeprom(btv);
+			if (-1 != type) {
+				btv->type = type;
+			} else if (btv->id <= 849) {
+				/* for unknown bt848, assume old Hauppauge */
 			        btv->type=BTTV_HAUPPAUGE;
+			}
 
+		/* STB cards have a eeprom @ 0xae */
 		} else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) {
 			btv->type=BTTV_STB;
+		}
 
-#if 0	/* bad idea: 0xc0 is used for the tuner on _many_ boards */
-		} else if (I2CRead(btv, I2C_VHX)>=0) {
-			btv->type=BTTV_VHX;
-#endif
-
-		} else {
-			if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */
+#if 0
+		/* check for msp34xx */
+			if (I2CRead(btv, 0x80, "msp3400")>=0)
 				btv->type = BTTV_MIROPRO;
 			else
-	 			btv->type = BTTV_MIRO;
-		}
-	}
-
-#if 1
-	/* DEBUG: dump eeprom content if available */
-	if (I2CRead(btv, 0xa0, "eeprom")>=0) {
-		dump_eeprom(btv,0xa0);
-	}
+				btv->type = BTTV_MIRO;
 #endif
+	}
 
 	/* print which board we have found */
 	printk(KERN_INFO "bttv%d: model: ",btv->nr);
@@ -2955,8 +3107,12 @@
                 btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
         }
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
-                hauppauge_msp_reset(btv);
+		if (0xa0 != eeprom) {
+			eeprom = 0xa0;
+			readee(btv,eeprom_data,0xa0);
+		}
                 hauppauge_eeprom(btv);
+                hauppauge_boot_msp34xx(btv);
         }
 	if (btv->type == BTTV_MAXI) {
 		/* PHILIPS FI1216MK2 tuner (PAL/SECAM) */
@@ -2973,7 +3129,11 @@
 	    btv->type == BTTV_CONFERENCETV	||
 	    btv->type == BTTV_PIXVIEWPLAYTV	||
 	    btv->type == BTTV_AVERMEDIA98	||
-	    btv->type == BTTV_MAGICTVIEW061) {
+	    btv->type == BTTV_MAGICTVIEW061	||
+	    btv->type == BTTV_CHRONOS_VS2	||
+	    btv->type == BTTV_TYPHOON_TVIEW	||
+	    btv->type == BTTV_PXELVWPLTVPRO     ||
+	    btv->type == BTTV_WINFAST2000) {
                 btv->pll.pll_ifreq=28636363;
                 btv->pll.pll_crystal=BT848_IFORM_XT0;
         }
@@ -3005,7 +3165,7 @@
 	if (tvcards[btv->type].tda985x &&
 	    I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) {
 		if (autoload)
-			request_module("tda9855");
+			request_module("tda985x");
 	}
 
 	if (tvcards[btv->type].tea63xx /* &&
@@ -3023,9 +3183,19 @@
 }
 
 
-static void bt848_set_risc_jmps(struct bttv *btv)
+static void bt848_set_risc_jmps(struct bttv *btv, int flags)
 {
-	int flags=btv->cap;
+	if (-1 == flags) {
+		/* defaults */
+		flags = 0;
+		if (btv->scr_on)
+			flags |= 0x03;
+		if (btv->vbi_on)
+			flags |= 0x0c;
+	}
+
+	if (debug) printk("bttv%d: set_risc_jmp %08lx:",
+			  btv->nr,virt_to_bus(btv->risc_jmp));
 
 	/* Sync to start of odd field */
 	btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
@@ -3034,17 +3204,27 @@
 
 	/* Jump to odd vbi sub */
 	btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20));
-	if (flags&8)
+	if (flags&8) {
+		if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd));
 		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd));
-	else
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
+	}
 
         /* Jump to odd sub */
 	btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20));
-	if (flags&2)
-		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd));
-	else
+	if (0 != btv->risc_cap_odd) {
+		if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd);
+		flags |= 3;
+		btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd);
+	} else if (flags&2) {
+		if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
+		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd));
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6));
+	}
 
 
 	/* Sync to start of even field */
@@ -3054,22 +3234,34 @@
 
 	/* Jump to even vbi sub */
 	btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
-	if (flags&4)
+	if (flags&4) {
+		if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even));
 		btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even));
-	else
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
+	}
 
 	/* Jump to even sub */
 	btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20));
-	if (flags&1)
-		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even));
-	else
+	if (0 != btv->risc_cap_even) {
+		if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even);
+		flags |= 3;
+		btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even);
+	} else if (flags&1) {
+		if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
+		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even));
+	} else {
+		if (debug) printk(" -----------");
 		btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12));
+	}
 
 	btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
 	btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
 
 	/* enable cpaturing and DMA */
+	if (debug) printk(" flags=0x%x dma=%s\n",
+			  flags,(flags&0x0f) ? "on" : "off");
 	btaor(flags, ~0x0f, BT848_CAP_CTL);
 	if (flags&0x0f)
 		bt848_dma(btv, 3);
@@ -3110,24 +3302,29 @@
 static int init_bt848(int i)
 {
         struct bttv *btv = &bttvs[i];
+	int j;
 
 	btv->user=0; 
         init_MUTEX(&btv->lock);
 
-#if 0
 	/* dump current state of the gpio registers before changing them,
 	 * might help to make a new card work */
-	printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n",
-		i,
-		btread(BT848_GPIO_OUT_EN),
-		btread(BT848_GPIO_DATA),
-		btread(BT848_GPIO_REG_INP));
-#endif
+	if (verbose >= 2)
+		printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n",
+		       i,
+		       btread(BT848_GPIO_OUT_EN),
+		       btread(BT848_GPIO_DATA),
+		       btread(BT848_GPIO_REG_INP));
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
 	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem));
 
+	/* not registered yet */
+	btv->video_dev.minor = -1;
+	btv->radio_dev.minor = -1;
+	btv->vbi_dev.minor = -1;
+
 	/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
 	btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */
 	btv->win.interlace=1;
@@ -3135,10 +3332,6 @@
 	btv->win.y=0;
 	btv->win.width=768; /* 640 */
 	btv->win.height=576; /* 480 */
-	btv->win.cropwidth=768; /* 640 */
-	btv->win.cropheight=576; /* 480 */
-	btv->win.cropx=0;
-	btv->win.cropy=0;
 	btv->win.bpp=2;
 	btv->win.depth=16;
 	btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
@@ -3146,27 +3339,24 @@
 	btv->win.swidth=1024;
 	btv->win.sheight=768;
 	btv->win.vidadr=0;
-	btv->cap=0;
+	btv->vbi_on=0;
+	btv->scr_on=0;
 
-	btv->gmode=0;
-	btv->risc_odd=0;
-	btv->risc_even=0;
+	btv->risc_scr_odd=0;
+	btv->risc_scr_even=0;
+	btv->risc_cap_odd=0;
+	btv->risc_cap_even=0;
 	btv->risc_jmp=0;
 	btv->vbibuf=0;
-	btv->grisc=0;
-	btv->grabbing=0;
-	btv->grabcount=0;
-	btv->grab=0;
-	btv->lastgrab=0;
         btv->field=btv->last_field=0;
 
 	/* i2c */
         btv->tuner_type=-1;
         init_bttv_i2c(btv);
 
-	if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+	if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
-	if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+	if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
 	if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL)))
 		return -1;
@@ -3180,9 +3370,13 @@
 	btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
 	if (!btv->vbibuf) 
 		return -1;
-	if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL)))
+	if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL)))
 		return -1;
-
+	for (j = 0; j < gbuffers; j++) {
+		if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL)))
+			return -1;
+	}
+	
 	memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random
 	                                        memory to the user */
 
@@ -3194,7 +3388,14 @@
 /*	btwrite(0, BT848_TDEC); */
         btwrite(0x10, BT848_COLOR_CTL);
 	btwrite(0x00, BT848_CAP_CTL);
-	btwrite(0xac, BT848_GPIO_DMA_CTL);
+	/* set planar and packed mode trigger points and         */
+	/* set rising edge of inverted GPINTR pin as irq trigger */
+	btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+		BT848_GPIO_DMA_CTL_PLTP1_16|
+		BT848_GPIO_DMA_CTL_PLTP23_16|
+		BT848_GPIO_DMA_CTL_GPINTC|
+		BT848_GPIO_DMA_CTL_GPINTI, 
+		BT848_GPIO_DMA_CTL);
 
         /* select direct input */
 	btwrite(0x00, BT848_GPIO_REG_INP);
@@ -3229,13 +3430,14 @@
                 /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
                   BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
                 (fieldnr ? BT848_INT_VSYNC : 0)|
+		BT848_INT_GPINT|
 		BT848_INT_SCERR|
 		BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
 		BT848_INT_MASK);
 
 	make_vbitab(btv);
-	bt848_set_risc_jmps(btv);
+	bt848_set_risc_jmps(btv,-1);
   
 	/*
 	 *	Now add the template and register the device unit.
@@ -3262,12 +3464,17 @@
 		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\n", btv->nr, astat));
+		IDEBUG(printk ("bttv%d:  stat=%08x\n", btv->nr, stat));
 
 		/* get device status bits */
 		dstat=btread(BT848_DSTATUS);
     
+		if (astat&BT848_INT_GPINT) {
+			IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr));
+			wake_up_interruptible(&btv->gpioq);
+		}
+
 		if (astat&BT848_INT_FMTCHG) 
 		{
 			IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
@@ -3283,13 +3490,21 @@
 			IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
                         btv->field++;
 		}
-		if (astat&BT848_INT_SCERR) {
-			IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
-			bt848_dma(btv, 0);
-			bt848_dma(btv, 1);
+		if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
+			printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr,
+			       (astat&BT848_INT_SCERR) ? " SCERR" : "",
+			       (astat&BT848_INT_OCERR) ? " OCERR" : "",
+			       btread(BT848_RISC_COUNT));
+			bt848_set_risc_jmps(btv,0);
+			btwrite(0, BT848_SRESET);
+			btwrite(virt_to_bus(btv->risc_jmp),
+				BT848_RISC_STRT_ADD);
+			bt848_set_geo(btv,0);
+			bt848_set_risc_jmps(btv,-1);
+#if 0
 			wake_up_interruptible(&btv->vbiq);
 			wake_up_interruptible(&btv->capq);
-
+#endif
 		}
 		if (astat&BT848_INT_RISCI) 
 		{
@@ -3307,41 +3522,48 @@
 			/* captured full frame */
 			if (stat&(2<<28)) 
 			{
-				/*wake_up_interruptible(&btv->capq);*/
                                 btv->last_field=btv->field;
-			        btv->grab++;
-                                btv->frame_stat[btv->grf] = GBUFFER_DONE;
-			        if ((--btv->grabbing))
+				if (debug)
+					printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab);
+				btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE;
+				btv->gq_grab = -1;
+			        if (btv->gq_in != btv->gq_out)
 				{
-					btv->gfmt = btv->gfmt_next;
-					btv->gwidth = btv->gwidth_next;
-					btv->gheight = btv->gheight_next;
-					btv->gro = btv->gro_next;
-					btv->gre = btv->gre_next;
-					btv->grf = btv->grf_next;
-                                        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,0);
+					btv->gq_grab = btv->gqueue[btv->gq_out++];
+					btv->gq_out  = btv->gq_out % MAX_GBUFFERS;
+					if (debug)
+						printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab);
+                                        btv->risc_cap_odd  = btv->gbuf[btv->gq_grab].ro;
+					btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
+					bt848_set_risc_jmps(btv,-1);
+					bt848_set_geo(btv,0);
+					btwrite(BT848_COLOR_CTL_GAMMA,
+						BT848_COLOR_CTL);
 				} else {
-					bt848_set_risc_jmps(btv);
+                                        btv->risc_cap_odd  = 0;
+					btv->risc_cap_even = 0;
+					bt848_set_risc_jmps(btv,-1);
 					btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
 					btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
-                                        bt848_set_geo(btv, btv->win.width, 
-						      btv->win.height,
-						      btv->win.color_fmt,0);
+                                        bt848_set_geo(btv,0);
+					btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA,
+						BT848_COLOR_CTL);
 				}
 				wake_up_interruptible(&btv->capq);
 				break;
 			}
 			if (stat&(8<<28)) 
 			{
-			        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,0);
+				btv->gq_grab = btv->gqueue[btv->gq_out++];
+				btv->gq_out  = btv->gq_out % MAX_GBUFFERS;
+				if (debug)
+					printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab);
+				btv->risc_cap_odd  = btv->gbuf[btv->gq_grab].ro;
+				btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
+				bt848_set_risc_jmps(btv,-1);
+				bt848_set_geo(btv,0);
+				btwrite(BT848_COLOR_CTL_GAMMA,
+					BT848_COLOR_CTL);
 			}
 		}
 		if (astat&BT848_INT_OCERR) 
@@ -3427,6 +3649,9 @@
         init_waitqueue_head(&btv->capqe);
         btv->vbip=VBIBUF_SIZE;
 
+	init_waitqueue_head(&btv->gpioq);
+	btv->shutdown=0;
+
         btv->id=dev->device;
         btv->irq=dev->irq;
         btv->bt848_adr=dev->resource[0].start;
@@ -3544,15 +3769,17 @@
 static void release_bttv(void)
 {
 	u8 command;
-	int i;
+	int i,j;
 	struct bttv *btv;
 
 	for (i=0;i<bttv_num; i++) 
 	{
 		btv=&bttvs[i];
 
-		/* turn off all capturing, DMA and IRQs */
+    		/* unregister i2c_bus */
+                i2c_bit_del_bus(&btv->i2c_adap);
 
+		/* turn off all capturing, DMA and IRQs */
 		btand(~15, BT848_GPIO_DMA_CTL);
 
 		/* first disable interrupts before unmapping the memory! */
@@ -3560,9 +3787,6 @@
 		btwrite(0xffffffffUL,BT848_INT_STAT);
 		btwrite(0x0, BT848_GPIO_OUT_EN);
 
-    		/* unregister i2c_bus */
-                i2c_bit_del_bus(&btv->i2c_adap);
-
 		/* disable PCI bus-mastering */
 		pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
 		/* Should this be &=~ ?? */
@@ -3570,14 +3794,17 @@
 		pci_write_config_byte(btv->dev, PCI_COMMAND, command);
     
 		/* unmap and free memory */
-		if (btv->grisc)
-		        kfree((void *) btv->grisc);
+		for (j = 0; j < gbuffers; j++)
+			if (btv->gbuf[j].risc)
+				kfree(btv->gbuf[j].risc);
+		if (btv->gbuf)
+		        kfree((void *) btv->gbuf);
 
-		if (btv->risc_odd)
-			kfree((void *) btv->risc_odd);
+		if (btv->risc_scr_odd)
+			kfree((void *) btv->risc_scr_odd);
 			
-		if (btv->risc_even)
-			kfree((void *) btv->risc_even);
+		if (btv->risc_scr_even)
+			kfree((void *) btv->risc_scr_even);
 
 		DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp));
 		if (btv->risc_jmp)
@@ -3599,6 +3826,13 @@
 			video_unregister_device(&btv->vbi_dev);
 		if (radio[btv->nr] && btv->radio_dev.minor != -1)
 			video_unregister_device(&btv->radio_dev);
+
+       		/* wake up any waiting processes
+		   because shutdown flag is set, no new processes (in this queue) 
+		   are expected
+		*/
+		btv->shutdown=1;
+		wake_up(&btv->gpioq);
 	}
 }
 
@@ -3614,6 +3848,14 @@
 	       (BTTV_VERSION_CODE >> 16) & 0xff,
 	       (BTTV_VERSION_CODE >> 8) & 0xff,
 	       BTTV_VERSION_CODE & 0xff);
+	if (gbuffers < 2 || gbuffers > MAX_GBUFFERS)
+		gbuffers = 2;
+	if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+		gbufsize = BTTV_MAX_FBUF;
+	if (verbose)
+		printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n",
+		       gbuffers,gbufsize/1024,gbuffers*gbufsize/1024);
+
 	handle_chipset();
 	if (find_bt848()<=0)
 		return -EIO;
diff -u --recursive --new-file v2.3.49/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.3.49/linux/drivers/char/bttv.h	Tue Jan 11 22:31:39 2000
+++ linux/drivers/char/bttv.h	Mon Mar  6 15:32:30 2000
@@ -21,45 +21,67 @@
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#define BTTV_VERSION_CODE 0x00070d
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,21) 
 
 #include <linux/types.h>
 #include <linux/wait.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 
 #include "audiochip.h"
 #include "bt848.h"
 
+#define WAIT_QUEUE                 wait_queue_head_t
 
-/* experimental, interface might change */
-#ifndef VIDIOCSWIN2
-#define VIDIOCSWIN2 _IOW('v',28,struct video_window2)
-struct video_window2
-{
-	__u16   palette;                /* Palette (aka video format) in use */
-	__u32   start;                  /* start address, relative to video_buffer.base */
-	__u32   pitch;
-	__u32   width;
-	__u32   height;
-	__u32   flags;
-	
-	struct	video_clip *clips;
-	int	clipcount;
-};
-#endif
-
+/* returns card type, 
+   for possible values see lines below beginning with #define BTTV_UNKNOWN
+   returns negative value if error ocurred 
+*/
+extern int bttv_get_id(unsigned int card);
+
+/* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
+   data | (current_GPOE_value & ~mask)
+   returns negative value if error ocurred
+*/
+extern int bttv_gpio_enable(unsigned int card,
+			    unsigned long mask, unsigned long data);
+
+/* fills data with GPDATA register contents
+   returns negative value if error ocurred
+*/
+extern int bttv_read_gpio(unsigned int card, unsigned long *data);
+
+/* sets GPDATA register to new value:
+  (data & mask) | (current_GPDATA_value & ~mask)
+  returns negative value if error ocurred 
+*/
+extern int bttv_write_gpio(unsigned int card, 
+			    unsigned long mask, unsigned long data);
+
+/* returns pointer to task queue which can be used as parameter to 
+   interruptible_sleep_on
+   in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
+   (wake_up_interruptible) and following call to the function bttv_read_gpio 
+   should return new value of GPDATA,
+   returns NULL value if error ocurred or queue is not available
+   WARNING: because there is no buffer for GPIO data, one MUST 
+   process data ASAP
+*/
+extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card);
 
-#define WAIT_QUEUE                 wait_queue_head_t
 
 #ifndef O_NONCAP  
 #define O_NONCAP	O_TRUNC
 #endif
 
-#define MAX_GBUFFERS	2
+#define MAX_GBUFFERS	64
 #define RISCMEM_LEN	(32744*2)
 #define VBI_MAXLINES    16
 #define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
 
 #define BTTV_MAX_FBUF	0x208000
+#define I2C_CLIENTS_MAX 8
 
 #ifdef __KERNEL__
 
@@ -69,17 +91,12 @@
 	ushort width, height;
 	ushort bpp, bpl;
 	ushort swidth, sheight;
-	short cropx, cropy;
-	ushort cropwidth, cropheight;
 	unsigned long vidadr;
 	ushort freq;
 	int norm;
 	int interlace;
 	int color_fmt;
 	ushort depth;
-
-	int use_yuv;
-	struct video_window2 win2;
 };
 
 struct bttv_pll_info {
@@ -89,7 +106,21 @@
 	unsigned int pll_current;  /* Currently programmed ofreq */
 };
 
-#define I2C_CLIENTS_MAX 8
+struct bttv_gbuf {
+	int stat;
+#define GBUFFER_UNUSED       0
+#define GBUFFER_GRABBING     1
+#define GBUFFER_DONE         2
+#define GBUFFER_ERROR        3
+
+	u16 width;
+	u16 height;
+	u16 fmt;
+	
+	u32 *risc;
+	unsigned long ro;
+	unsigned long re;
+};
 
 struct bttv
 {
@@ -125,6 +156,7 @@
   
 	unsigned char *vbibuf;
 	struct bttv_window win;
+	int fb_color_ctl;
 	int type;            /* card type  */
 	int audio;           /* audio mode */
 	int audio_chip;      /* set to one of the chips supported by bttv.c */
@@ -141,34 +173,18 @@
 	WAIT_QUEUE capqe;
 	int vbip;
 
-	u32 *risc_odd;
-	u32 *risc_even;
-	int cap;
+	u32 *risc_scr_odd;
+	u32 *risc_scr_even;
+	u32 risc_cap_odd;
+	u32 risc_cap_even;
+	int scr_on;
+	int vbi_on;
 	struct video_clip *cliprecs;
 
-	struct gbuffer *ogbuffers;
-	struct gbuffer *egbuffers;
-	u16 gwidth, gheight, gfmt;
-	u16 gwidth_next, gheight_next, gfmt_next;
-	u32 *grisc;
-	
-	unsigned long gro;
-	unsigned long gre;
-	unsigned long gro_next;
-	unsigned long gre_next;
-
-        int grf,grf_next;  /* frame numbers in grab queue */
-        int frame_stat[MAX_GBUFFERS];
-#define GBUFFER_UNUSED       0
-#define GBUFFER_GRABBING     1
-#define GBUFFER_DONE         2
-
+	struct bttv_gbuf *gbuf;
+	int gqueue[MAX_GBUFFERS];
+	int gq_in,gq_out,gq_grab;
         char *fbuffer;
-	int gmode;
-	int grabbing;
-	int lastgrab;
-	int grab;
-	int grabcount;
 
 	struct bttv_pll_info pll;
 	unsigned int Fsc;
@@ -176,12 +192,12 @@
 	unsigned int last_field; /* number of last grabbed field */
 	int i2c_command;
 	int triton1;
+
+	WAIT_QUEUE gpioq;
+	int shutdown;
 };
 #endif
 
-/*The following should be done in more portable way. It depends on define
-  of _ALPHA_BTTV in the Makefile.*/
-
 #if defined(__powerpc__) /* big-endian */
 extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
 {
@@ -193,14 +209,9 @@
 #define btwrite(dat,adr)  io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
 #define btread(adr)       ld_le32((unsigned *)(btv->bt848_mem+(adr)))
 #else
-#ifdef _ALPHA_BTTV
-#define btwrite(dat,adr)    writel((dat),(char *) (btv->bt848_adr+(adr)))
-#define btread(adr)         readl(btv->bt848_adr+(adr))
-#else
 #define btwrite(dat,adr)    writel((dat), (char *) (btv->bt848_mem+(adr)))
 #define btread(adr)         readl(btv->bt848_mem+(adr))
 #endif
-#endif
 
 #define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
 #define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
@@ -243,10 +254,19 @@
 #define BTTV_PHOEBE_TVMAS  0x16
 #define BTTV_MODTEC_205    0x17
 #define BTTV_MAGICTVIEW061 0x18
-
+#define BTTV_VOBIS_BOOSTAR 0x19
+#define BTTV_HAUPPAUG_WCAM 0x1a
 #define BTTV_MAXI          0x1b
 #define BTTV_TERRATV       0x1c
 #define BTTV_PXC200        0x1d
+#define BTTV_FLYVIDEO_98   0x1e
+#define BTTV_IPROTV        0x1f
+#define BTTV_INTEL_C_S_PCI 0x20
+#define BTTV_TERRATVALUE   0x21
+#define BTTV_WINFAST2000   0x22
+#define BTTV_CHRONOS_VS2   0x23
+#define BTTV_TYPHOON_TVIEW 0x24
+#define BTTV_PXELVWPLTVPRO 0x25
 
 
 #define AUDIO_TUNER        0x00
@@ -279,27 +299,6 @@
 #define TDA9840_STADJ      0x03
 #define TDA9840_TEST       0x04
 
-#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
-
-#define TDA8425_VL         0x00
-#define TDA8425_VR         0x01
-#define TDA8425_BA         0x02
-#define TDA8425_TR         0x03
-#define TDA8425_S1         0x08
- 
-#define TEA6300_VL         0x00		/* volume control left */
-#define TEA6300_VR         0x01		/* volume control right */
-#define TEA6300_BA         0x02		/* bass control */
-#define TEA6300_TR         0x03		/* treble control */
-#define TEA6300_FA         0x04		/* fader control */
-#define TEA6300_SW         0x05		/* mute and source switch */
-
 #define PT2254_L_CHANEL 0x10
 #define PT2254_R_CHANEL 0x08
 #define PT2254_DBS_IN_2 0x400
@@ -309,3 +308,9 @@
 #define WINVIEW_PT2254_STROBE 0x80
 
 #endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.3.49/linux/drivers/char/console.c	Sun Feb 20 21:12:38 2000
+++ linux/drivers/char/console.c	Tue Mar  7 11:07:42 2000
@@ -2564,7 +2564,7 @@
 	int i;
 
 	for (i = 0; i < console_driver.num; i++)
-		tty_register_devfs (&console_driver, 0,
+		tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY,
 				    console_driver.minor_start + i);
 }
 
diff -u --recursive --new-file v2.3.49/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.3.49/linux/drivers/char/epca.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/char/epca.c	Fri Mar  3 12:54:44 2000
@@ -1545,12 +1545,13 @@
 } /* End init_module */
 
 #endif
-#ifdef MODULE
-/* -------------------- Begin cleanup_module  ---------------------- */
 
 #ifdef ENABLE_PCI
 static struct pci_driver epca_driver;
 #endif
+
+#ifdef MODULE
+/* -------------------- Begin cleanup_module  ---------------------- */
 
 void cleanup_module()
 { /* Begin cleanup_module */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.3.49/linux/drivers/char/istallion.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/istallion.c	Fri Mar  3 12:54:44 2000
@@ -142,6 +142,8 @@
  */
 #define	STLI_EISAPROBE	0
 
+static devfs_handle_t devfs_handle = NULL;
+
 /*****************************************************************************/
 
 /*
@@ -829,8 +831,6 @@
 }
 
 /*****************************************************************************/
-
-static devfs_handle_t devfs_handle = NULL;
 
 void cleanup_module()
 {
diff -u --recursive --new-file v2.3.49/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.3.49/linux/drivers/char/msp3400.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/msp3400.c	Mon Mar  6 15:32:30 2000
@@ -480,7 +480,7 @@
 		break;
 	case VIDEO_SOUND_MONO:
 		if (msp->mode == MSP_MODE_AM_NICAM) {
-			printk("msp3400: switching to AM mono\n");
+			dprintk("msp3400: switching to AM mono\n");
 			/* AM mono decoding is handled by tuner, not MSP chip */
 			/* so let's redirect sound from tuner via SCART */
 			/* volume prescale for SCART */
@@ -723,7 +723,7 @@
 
 		/* some time for the tuner to sync */
 		current->state   = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
+		schedule_timeout(HZ/5);
 		if (signal_pending(current))
 			goto done;
 		
@@ -750,13 +750,15 @@
 			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
 
 			current->state   = TASK_INTERRUPTIBLE;
-			schedule_timeout(HZ/25);
+			schedule_timeout(HZ/10);
 			if (signal_pending(current))
 				goto done;
 			if (msp->restart)
 				msp->restart = 0;
 
 			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
+			if (val > 32768)
+				val -= 65536;
 			if (val1 < val)
 				val1 = val, max1 = this;
 			dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
@@ -785,13 +787,15 @@
 			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
 
 			current->state   = TASK_INTERRUPTIBLE;
-			schedule_timeout(HZ/25);
+			schedule_timeout(HZ/10);
 			if (signal_pending(current))
 				goto done;
 			if (msp->restart)
 				goto restart;
 
 			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
+			if (val > 32768)
+				val -= 65536;
 			if (val2 < val)
 				val2 = val, max2 = this;
 			dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
@@ -974,7 +978,7 @@
 	
 		/* some time for the tuner to sync */
 		current->state   = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
+		schedule_timeout(HZ/5);
 		if (signal_pending(current))
 			goto done;
 
@@ -1041,10 +1045,9 @@
 		for (i = 0; modelist[i].name != NULL; i++)
 			 if (modelist[i].retval == val)
 				break;
-		if (debug)
-			printk("msp3410: current mode: %s (0x%04x)\n",
-				modelist[i].name ? modelist[i].name : "unknown",
-				val);
+		dprintk("msp3410: current mode: %s (0x%04x)\n",
+			modelist[i].name ? modelist[i].name : "unknown",
+			val);
 		msp->main   = modelist[i].main;
 		msp->second = modelist[i].second;
 
@@ -1242,6 +1245,7 @@
 msp3400c_mixer_open(struct inode *inode, struct file *file)
 {
         int minor = MINOR(inode->i_rdev);
+	struct i2c_client *client;
 	struct msp3400c *msp;
 	int i;
 
@@ -1249,12 +1253,17 @@
 	for (i = 0; i < MSP3400_MAX; i++) {
 		msp = msps[i]->data;
 		if (msp->mixer_num == minor) {
-			file->private_data = msps[i];
+			client = msps[i];
+			file->private_data = client;
 			break;
 		}
 	}
 	if (MSP3400_MAX == i)
 		return -ENODEV;
+
+	/* lock bttv in memory while the mixer is in use  */
+	if (client->adapter->inc_use)
+		client->adapter->inc_use(client->adapter);
 	
         MOD_INC_USE_COUNT;
         return 0;
@@ -1263,6 +1272,10 @@
 static int
 msp3400c_mixer_release(struct inode *inode, struct file *file)
 {
+	struct i2c_client *client = file->private_data;
+
+	if (client->adapter->inc_use) 
+		client->adapter->inc_use(client->adapter);
         MOD_DEC_USE_COUNT;
         return 0;
 }
@@ -1274,10 +1287,10 @@
 }
 
 static struct file_operations msp3400c_mixer_fops = {
-	llseek:		msp3400c_mixer_llseek,
-	ioctl:		msp3400c_mixer_ioctl,
-	open:		msp3400c_mixer_open,
-	release:	msp3400c_mixer_release,
+	llseek:         msp3400c_mixer_llseek,
+	ioctl:          msp3400c_mixer_ioctl,
+	open:           msp3400c_mixer_open,
+	release:        msp3400c_mixer_release,
 };
 
 #endif
diff -u --recursive --new-file v2.3.49/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.49/linux/drivers/char/ppdev.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/char/ppdev.c	Tue Mar  7 11:04:12 2000
@@ -83,7 +83,7 @@
 /* ROUND_UP macro from fs/select.c */
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 
-static inline void enable_irq (struct pp_struct *pp)
+static inline void pp_enable_irq (struct pp_struct *pp)
 {
 	struct parport *port = pp->pdev->port;
 	port->ops->enable_irq (port);
@@ -144,7 +144,7 @@
 	}
 
 	kfree (kbuffer);
-	enable_irq (pp);
+	pp_enable_irq (pp);
 	return bytes_read;
 }
 
@@ -197,7 +197,7 @@
 	}
 
 	kfree (kbuffer);
-	enable_irq (pp);
+	pp_enable_irq (pp);
 	return bytes_written;
 }
 
@@ -292,7 +292,7 @@
 
 		/* For interrupt-reporting to work, we need to be
 		 * informed of each interrupt. */
-		enable_irq (pp);
+		pp_enable_irq (pp);
 
 		/* We may need to fix up the state machine. */
 		info = &pp->pdev->port->ieee1284;
@@ -441,7 +441,7 @@
 			ret = -ENXIO;
 			break;
 		}
-		enable_irq (pp);
+		pp_enable_irq (pp);
 		return ret;
 
 	case PPWCTLONIRQ:
diff -u --recursive --new-file v2.3.49/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.3.49/linux/drivers/char/pty.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/char/pty.c	Tue Mar  7 11:07:42 2000
@@ -329,9 +329,10 @@
 	clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
 	wake_up_interruptible(&pty->open_wait);
 	set_bit(TTY_THROTTLED, &tty->flags);
-	/*  register a slave for the master  */
+	/*  Register a slave for the master  */
 	if (tty->driver.major == PTY_MASTER_MAJOR)
-		tty_register_devfs(&tty->link->driver, DEVFS_FL_WAIT,
+		tty_register_devfs(&tty->link->driver,
+				   DEVFS_FL_AUTO_OWNER | DEVFS_FL_WAIT,
 				   tty->link->driver.minor_start +
 				   MINOR(tty->device)-tty->driver.minor_start);
 	retval = 0;
diff -u --recursive --new-file v2.3.49/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- v2.3.49/linux/drivers/char/sh-sci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sh-sci.c	Sun Mar  5 09:34:33 2000
@@ -0,0 +1,992 @@
+/* $Id: sh-sci.c,v 1.32 2000-03-05 13:56:18+09 gniibe Exp $
+ *
+ *  linux/drivers/char/sh-sci.c
+ *
+ *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+ *  Copyright (C) 1999, 2000  Niibe Yutaka
+ *
+ * TTY code is based on sx.c (Specialix SX driver) by:
+ *
+ *   (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include "generic_serial.h"
+#include "sh-sci.h"
+
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+static void gdb_detach(void);
+#endif
+
+struct sci_port sci_ports[1];
+
+/* Function prototypes */
+static void sci_disable_tx_interrupts(void *ptr);
+static void sci_enable_tx_interrupts(void *ptr);
+static void sci_disable_rx_interrupts(void *ptr);
+static void sci_enable_rx_interrupts(void *ptr);
+static int  sci_get_CD(void *ptr);
+static void sci_shutdown_port(void *ptr);
+static void sci_set_real_termios(void *ptr);
+static void sci_hungup(void *ptr);
+static void sci_close(void *ptr);
+static int sci_chars_in_buffer(void *ptr);
+static int sci_init_drivers(void);
+
+static struct tty_driver sci_driver, sci_callout_driver;
+
+#define SCI_NPORTS 1
+static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, };
+static struct termios *sci_termios[2]; /* nomal, locked */
+
+int sci_refcount;
+int sci_debug = 0;
+
+#ifdef MODULE
+MODULE_PARM(sci_debug, "i");
+#endif
+
+static struct real_driver sci_real_driver = {
+	sci_disable_tx_interrupts,
+	sci_enable_tx_interrupts,
+	sci_disable_rx_interrupts,
+	sci_enable_rx_interrupts,
+	sci_get_CD,
+	sci_shutdown_port,
+	sci_set_real_termios,
+	sci_chars_in_buffer,
+	sci_close,
+	sci_hungup,
+	NULL
+};
+
+static void sci_setsignals(struct sci_port *port, int dtr, int rts)
+{
+	/* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
+	/* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
+	/* If you have signals for DTR and DCD, please implement here. */
+	;
+}
+
+static int sci_getsignals(struct sci_port *port)
+{
+	/* This routine is used for geting signals of: DTR, DCD, DSR, RI,
+	   and CTS/RTS */
+
+	return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR;
+/*
+	(((o_stat & OP_DTR)?TIOCM_DTR:0) |
+	 ((o_stat & OP_RTS)?TIOCM_RTS:0) |
+	 ((i_stat & IP_CTS)?TIOCM_CTS:0) |
+	 ((i_stat & IP_DCD)?TIOCM_CAR:0) |
+	 ((i_stat & IP_DSR)?TIOCM_DSR:0) |
+	 ((i_stat & IP_RI) ?TIOCM_RNG:0)
+*/
+}
+
+static void sci_set_baud(struct sci_port *port)
+{
+	int t;
+
+	switch (port->gs.baud) {
+	case 0:
+		t = -1;
+		break;
+	case 2400:
+		t = BPS_2400;
+		break;
+	case 4800:
+		t = BPS_4800;
+		break;
+	case 9600:
+		t = BPS_9600;
+		break;
+	case 19200:
+		t = BPS_19200;
+		break;
+	case 38400:
+		t = BPS_38400;
+		break;
+	default:
+		printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", port->gs.baud);
+	case 115200:
+		t = BPS_115200;
+		break;
+	}
+
+	if (t > 0) {
+		sci_setsignals (port, 1, -1); 
+		ctrl_outb(t, SCBRR);
+		ctrl_outw(0xa400, RFCR); /* Refresh counter clear */
+		while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER)
+			;
+	} else {
+		sci_setsignals (port, 0, -1);
+	}
+}
+
+static void sci_set_termios_cflag(struct sci_port *port)
+{
+	unsigned short status;
+	unsigned short smr_val=0;
+#if defined(CONFIG_SH_SCIF_SERIAL)
+	unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */
+#endif
+
+	do
+		status = ctrl_in(SC_SR);
+	while (!(status & SCI_TEND));
+
+	port->old_cflag = port->gs.tty->termios->c_cflag;
+
+	ctrl_out(0x00, SCSCR);	/* TE=0, RE=0, CKE1=0 */
+#if defined(CONFIG_SH_SCIF_SERIAL)
+	ctrl_out(fcr_val, SCFCR);
+	fcr_val = 0;
+#endif
+
+	if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7)
+		smr_val |= 0x40;
+	if (C_PARENB(port->gs.tty))
+		smr_val |= 0x20;
+	if (C_PARODD(port->gs.tty))
+		smr_val |= 0x10;
+	if (C_CSTOPB(port->gs.tty))
+		smr_val |= 0x08;
+	ctrl_out(smr_val, SCSMR);
+
+#if defined(CONFIG_SH_SCIF_SERIAL)
+	if (C_CRTSCTS(port->gs.tty))
+		fcr_val |= 0x08;
+	ctrl_out(fcr_val, SCFCR);
+#endif
+
+	sci_set_baud(port);
+	ctrl_out(SCSCR_INIT, SCSCR);	/* TIE=0,RIE=0,TE=1,RE=1 */
+#if 0 /* defined(CONFIG_SH_SCIF_SERIAL) */
+	ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */
+#endif
+	sci_enable_rx_interrupts(port);
+}
+
+static void sci_set_real_termios(void *ptr)
+{
+	struct sci_port *port = ptr;
+
+	if (port->old_cflag != port->gs.tty->termios->c_cflag)
+		sci_set_termios_cflag(port);
+
+	/* Tell line discipline whether we will do input cooking */
+	if (I_OTHER(port->gs.tty))
+		clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+	else
+		set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+
+/* Tell line discipline whether we will do output cooking.
+ * If OPOST is set and no other output flags are set then we can do output
+ * processing.  Even if only *one* other flag in the O_OTHER group is set
+ * we do cooking in software.
+ */
+	if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty))
+		set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+	else
+		clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+}
+
+/* ********************************************************************** *
+ *                   the interrupt related routines                       *
+ * ********************************************************************** */
+
+static void sci_transmit_chars(struct sci_port *port)
+{
+	int count, i;
+	int txroom;
+	unsigned long flags;
+	unsigned short status;
+	unsigned short ctrl;
+	unsigned char c;
+
+	status = ctrl_in(SC_SR);
+	if (!(status & SCI_TD_E)) {
+		save_and_cli(flags);
+		ctrl = ctrl_in(SCSCR);
+		if (port->gs.xmit_cnt == 0) {
+			ctrl &= ~SCI_CTRL_FLAGS_TIE;
+			port->gs.flags &= ~GS_TX_INTEN;
+		} else
+			ctrl |= SCI_CTRL_FLAGS_TIE;
+		ctrl_out(ctrl, SCSCR);
+		restore_flags(flags);
+		return;
+	}
+
+	while (1) {
+		count = port->gs.xmit_cnt;
+#if defined(CONFIG_SH_SCIF_SERIAL)
+		txroom = 16 - (ctrl_inw(SCFDR)>>8);
+#else
+		txroom = (ctrl_in(SC_SR)&SCI_TD_E)?1:0;
+#endif
+		if (count > txroom)
+			count = txroom;
+
+		/* Don't copy pas the end of the source buffer */
+		if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
+                	count = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
+
+		/* If for one reason or another, we can't copy more data, we're done! */
+		if (count == 0)
+			break;
+
+		for (i=0; i<count; i++) {
+			c = port->gs.xmit_buf[port->gs.xmit_tail + i];
+			ctrl_outb(c, SC_TDR);
+		}
+		ctrl_out(SCI_TD_E_CLEAR, SC_SR);
+
+		/* Update the kernel buffer end */
+		port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1);
+
+		/* This one last. (this is essential)
+		   It would allow others to start putting more data into the buffer! */
+		port->gs.xmit_cnt -= count;
+	}
+
+	if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    port->gs.tty->ldisc.write_wakeup)
+			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+		wake_up_interruptible(&port->gs.tty->write_wait);
+	}
+
+	save_and_cli(flags);
+	ctrl = ctrl_in(SCSCR);
+	if (port->gs.xmit_cnt == 0) {
+		ctrl &= ~SCI_CTRL_FLAGS_TIE;
+		port->gs.flags &= ~GS_TX_INTEN;
+	} else {
+#if defined(CONFIG_SH_SCIF_SERIAL)
+		ctrl_in(SC_SR); /* Dummy read */
+		ctrl_out(SCI_TD_E_CLEAR, SC_SR);
+#endif
+		ctrl |= SCI_CTRL_FLAGS_TIE;
+	}
+	ctrl_out(ctrl, SCSCR);
+	restore_flags(flags);
+}
+
+static inline void sci_receive_chars(struct sci_port *port)
+{
+	int i, count;
+	struct tty_struct *tty;
+	int copied=0;
+	unsigned short status;
+
+	status = ctrl_in(SC_SR);
+	if (!(status & SCI_RD_F))
+		return;
+
+	tty = port->gs.tty;
+	while (1) {
+#if defined(CONFIG_SH_SCIF_SERIAL)
+		count = ctrl_inw(SCFDR)&0x001f;
+#else
+		count = (ctrl_in(SC_SR)&SCI_RD_F)?1:0;
+#endif
+
+		/* Don't copy more bytes than there is room for in the buffer */
+		if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
+			count = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+		/* If for one reason or another, we can't copy more data, we're done! */
+		if (count == 0)
+			break;
+
+		for (i=0; i<count; i++)
+			tty->flip.char_buf_ptr[i] = ctrl_inb(SC_RDR);
+		ctrl_in(SC_SR); /* dummy read */
+		ctrl_out(SCI_RDRF_CLEAR, SC_SR);
+
+		memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
+
+		/* Update the kernel buffer end */
+		tty->flip.count += count;
+		tty->flip.char_buf_ptr += count;
+		tty->flip.flag_buf_ptr += count;
+
+		copied += count;
+	}
+
+	if (copied)
+		/* Tell the rest of the system the news. New characters! */
+		tty_flip_buffer_push(tty);
+}
+
+static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	struct sci_port *port = ptr;
+
+	if (port->gs.flags & GS_ACTIVE)
+		if (!(port->gs.flags & SCI_RX_THROTTLE))
+			sci_receive_chars(port);
+}
+
+static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	struct sci_port *port = ptr;
+
+	if (port->gs.flags & GS_ACTIVE)
+		if (port->gs.xmit_cnt) {
+			sci_transmit_chars(port);
+		}
+}
+
+static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	/* Handle errors */
+	if (ctrl_in(SC_SR) & SCI_ERRORS)
+		ctrl_out(SCI_ERROR_CLEAR, SC_SR);
+
+	/* Kick the transmission */
+	sci_tx_interrupt(irq, ptr, regs);
+}
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *              interface with the generic_serial driver                  *
+ * ********************************************************************** */
+
+static void sci_disable_tx_interrupts(void *ptr)
+{
+	unsigned long flags;
+	unsigned short ctrl;
+
+	/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+	save_and_cli(flags);
+	ctrl = ctrl_in(SCSCR);
+	ctrl &= ~SCI_CTRL_FLAGS_TIE;
+	ctrl_out(ctrl, SCSCR);
+	restore_flags(flags);
+}
+
+static void sci_enable_tx_interrupts(void *ptr)
+{
+	struct sci_port *port = ptr; 
+
+	disable_irq(SCI_TXI_IRQ);
+	sci_transmit_chars(port);
+	enable_irq(SCI_TXI_IRQ);
+}
+
+static void sci_disable_rx_interrupts(void * ptr)
+{
+	unsigned long flags;
+	unsigned short ctrl;
+
+	/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
+	save_and_cli(flags);
+	ctrl = ctrl_in(SCSCR);
+	ctrl &= ~SCI_CTRL_FLAGS_RIE;
+	ctrl_out(ctrl, SCSCR);
+	restore_flags(flags);
+}
+
+static void sci_enable_rx_interrupts(void * ptr)
+{
+	unsigned long flags;
+	unsigned short ctrl;
+
+	/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
+	save_and_cli(flags);
+	ctrl = ctrl_in(SCSCR);
+	ctrl |= SCI_CTRL_FLAGS_RIE;
+	ctrl_out(ctrl, SCSCR);
+	restore_flags(flags);
+}
+
+static int sci_get_CD(void * ptr)
+{
+	/* If you have signal for CD (Carrier Detect), please change here. */
+	return 1;
+}
+
+static int sci_chars_in_buffer(void * ptr)
+{
+#if defined(CONFIG_SH_SCIF_SERIAL)
+	return (ctrl_inw(SCFDR) >> 8) + ((ctrl_in(SC_SR) & SCI_TEND)? 0: 1);
+#else
+	return (ctrl_in(SC_SR) & SCI_TEND)? 0: 1;
+#endif
+}
+
+static void sci_shutdown_port(void * ptr)
+{
+	struct sci_port *port = ptr; 
+
+	port->gs.flags &= ~ GS_ACTIVE;
+	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL)
+		sci_setsignals(port, 0, 0);
+}
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *               interface with the rest of the system                    *
+ * ********************************************************************** */
+
+static int sci_open(struct tty_struct * tty, struct file * filp)
+{
+	struct sci_port *port;
+	int retval, line;
+
+	line = MINOR(tty->device) - SCI_MINOR_START;
+
+	if ((line < 0) || (line >= SCI_NPORTS))
+		return -ENODEV;
+
+	port = &sci_ports[line];
+
+	tty->driver_data = port;
+	port->gs.tty = tty;
+	port->gs.count++;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = gs_init_port(&port->gs);
+	if (retval) {
+		port->gs.count--;
+		return retval;
+	}
+
+	port->gs.flags |= GS_ACTIVE;
+	sci_setsignals(port, 1,1);
+
+	if (port->gs.count == 1) {
+		MOD_INC_USE_COUNT;
+	}
+
+	retval = block_til_ready(port, filp);
+
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		port->gs.count--;
+		return retval;
+	}
+
+	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = port->gs.normal_termios;
+		else 
+			*tty->termios = port->gs.callout_termios;
+		sci_set_real_termios(port);
+	}
+
+	sci_enable_rx_interrupts(port);
+
+	port->gs.session = current->session;
+	port->gs.pgrp = current->pgrp;
+
+	return 0;
+}
+
+static void sci_hungup(void *ptr)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void sci_close(void *ptr)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static int sci_ioctl(struct tty_struct * tty, struct file * filp, 
+                     unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	struct sci_port *port = tty->driver_data;
+	int ival;
+
+	rc = 0;
+	switch (cmd) {
+	case TIOCGSOFTCAR:
+		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+		              (unsigned int *) arg);
+		break;
+	case TIOCSSOFTCAR:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(int))) == 0) {
+			get_user(ival, (unsigned int *) arg);
+			tty->termios->c_cflag =
+				(tty->termios->c_cflag & ~CLOCAL) |
+				(ival ? CLOCAL : 0);
+		}
+		break;
+	case TIOCGSERIAL:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+		                      sizeof(struct serial_struct))) == 0)
+			gs_getserial(&port->gs, (struct serial_struct *) arg);
+		break;
+	case TIOCSSERIAL:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(struct serial_struct))) == 0)
+			rc = gs_setserial(&port->gs,
+					  (struct serial_struct *) arg);
+		break;
+	case TIOCMGET:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			ival = sci_getsignals(port);
+			put_user(ival, (unsigned int *) arg);
+		}
+		break;
+	case TIOCMBIS:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			get_user(ival, (unsigned int *) arg);
+			sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
+			                     ((ival & TIOCM_RTS) ? 1 : -1));
+		}
+		break;
+	case TIOCMBIC:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			get_user(ival, (unsigned int *) arg);
+			sci_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
+			                     ((ival & TIOCM_RTS) ? 0 : -1));
+		}
+		break;
+	case TIOCMSET:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			get_user(ival, (unsigned int *)arg);
+			sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
+			                     ((ival & TIOCM_RTS) ? 1 : 0));
+		}
+		break;
+
+	default:
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+
+	return rc;
+}
+
+static void sci_throttle(struct tty_struct * tty)
+{
+	struct sci_port *port = (struct sci_port *)tty->driver_data;
+
+	/* If the port is using any type of input flow
+	 * control then throttle the port.
+	 */
+	if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) )
+		port->gs.flags |= SCI_RX_THROTTLE;
+}
+
+static void sci_unthrottle(struct tty_struct * tty)
+{
+	struct sci_port *port = (struct sci_port *)tty->driver_data;
+
+	/* Always unthrottle even if flow control is not enabled on
+	 * this port in case we disabled flow control while the port
+	 * was throttled
+	 */
+	port->gs.flags &= ~SCI_RX_THROTTLE;
+	return;
+}
+
+/* ********************************************************************** *
+ *                    Here are the initialization routines.               *
+ * ********************************************************************** */
+
+static int sci_init_drivers(void)
+{
+	int error;
+	struct sci_port *port;
+
+	memset(&sci_driver, 0, sizeof(sci_driver));
+	sci_driver.magic = TTY_DRIVER_MAGIC;
+	sci_driver.driver_name = "serial";
+	sci_driver.name = "ttyS";
+	sci_driver.major = TTY_MAJOR;
+	sci_driver.minor_start = SCI_MINOR_START;
+	sci_driver.num = 1;
+	sci_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	sci_driver.subtype = SERIAL_TYPE_NORMAL;
+	sci_driver.init_termios = tty_std_termios;
+	sci_driver.init_termios.c_cflag =
+		B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+	sci_driver.flags = TTY_DRIVER_REAL_RAW;
+	sci_driver.refcount = &sci_refcount;
+	sci_driver.table = sci_table;
+	sci_driver.termios = &sci_termios[0];
+	sci_driver.termios_locked = &sci_termios[1];
+	sci_termios[0] = sci_termios[1] = NULL;
+
+	sci_driver.open	= sci_open;
+	sci_driver.close = gs_close;
+	sci_driver.write = gs_write;
+	sci_driver.put_char = gs_put_char;
+	sci_driver.flush_chars = gs_flush_chars;
+	sci_driver.write_room = gs_write_room;
+	sci_driver.chars_in_buffer = gs_chars_in_buffer;
+	sci_driver.flush_buffer = gs_flush_buffer;
+	sci_driver.ioctl = sci_ioctl;
+	sci_driver.throttle = sci_throttle;
+	sci_driver.unthrottle = sci_unthrottle;
+	sci_driver.set_termios = gs_set_termios;
+	sci_driver.stop = gs_stop;
+	sci_driver.start = gs_start;
+	sci_driver.hangup = gs_hangup;
+
+	sci_callout_driver = sci_driver;
+	sci_callout_driver.name = "cua";
+	sci_callout_driver.major = TTYAUX_MAJOR;
+	sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if ((error = tty_register_driver(&sci_driver))) {
+		printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	if ((error = tty_register_driver(&sci_callout_driver))) {
+		tty_unregister_driver(&sci_driver);
+		printk(KERN_ERR "sci: Couldn't register SCI callout driver, error = %d\n",
+		       error);
+		return 1;
+	}
+
+	port = &sci_ports[0];
+	port->gs.callout_termios = tty_std_termios;
+	port->gs.normal_termios	= tty_std_termios;
+	port->gs.magic = SCI_MAGIC;
+	port->gs.close_delay = HZ/2;
+	port->gs.closing_wait = 30 * HZ;
+	port->gs.rd = &sci_real_driver;
+	init_waitqueue_head(&port->gs.open_wait);
+	init_waitqueue_head(&port->gs.close_wait);
+	port->old_cflag = 0;
+
+	return 0;
+}
+
+#ifdef MODULE
+#define sci_init init_module
+#else
+#define sci_init rs_init
+#endif
+
+int __init sci_init(void)
+{
+	struct sci_port *port;
+	int i;
+
+	for (i=SCI_ERI_IRQ; i<SCI_IRQ_END; i++)
+		set_ipr_data(i, SCI_IPR_OFFSET, SCI_PRIORITY);
+
+	port = &sci_ports[0];
+
+	if (request_irq(SCI_ERI_IRQ, sci_er_interrupt, SA_INTERRUPT,
+			"serial", port)) {
+		printk(KERN_ERR "sci: Cannot allocate error irq.\n");
+		return -ENODEV;
+	}
+	if (request_irq(SCI_RXI_IRQ, sci_rx_interrupt, SA_INTERRUPT,
+			"serial", port)) {
+		printk(KERN_ERR "sci: Cannot allocate rx irq.\n");
+		return -ENODEV;
+	}
+	if (request_irq(SCI_TXI_IRQ, sci_tx_interrupt, SA_INTERRUPT,
+			"serial", port)) {
+		printk(KERN_ERR "sci: Cannot allocate tx irq.\n");
+		return -ENODEV;
+	}
+	/* XXX: How about BRI interrupt?? */
+
+	sci_init_drivers();
+
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+	gdb_detach();
+#endif
+	return 0;		/* Return -EIO when not detected */
+}
+
+#ifdef MODULE
+#undef func_enter
+#undef func_exit
+
+void cleanup_module(void)
+{
+	int i;
+
+	for (i=SCI_ERI_IRQ; i<SCI_TEI_IRQ; i++) /* XXX: irq_end?? */
+		free_irq(i, port);
+
+	tty_unregister_driver(&sci_driver);
+	tty_unregister_driver(&sci_callout_driver);
+}
+
+#include "generic_serial.c"
+#endif
+
+#ifdef CONFIG_SERIAL_CONSOLE
+/*
+ * ------------------------------------------------------------
+ * Serial console driver for SH-3/SH-4 SCI (with no FIFO)
+ * ------------------------------------------------------------
+ */
+
+static inline void put_char(char c)
+{
+	unsigned long flags;
+	unsigned short status;
+
+	save_and_cli(flags);
+
+	do
+		status = ctrl_in(SC_SR);
+	while (!(status & SCI_TD_E));
+
+	ctrl_outb(c, SC_TDR);
+	ctrl_out(SCI_TD_E_CLEAR, SC_SR);
+
+	restore_flags(flags);
+}
+
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+static int in_gdb = 1;
+
+static inline void handle_error(void)
+{				/* Clear error flags */
+	ctrl_out(SCI_ERROR_CLEAR, SC_SR);
+}
+
+static inline int get_char(void)
+{
+	unsigned long flags;
+	unsigned short status;
+	int c;
+
+	save_and_cli(flags);
+	do {
+		status = ctrl_in(SC_SR);
+		if (status & SCI_ERRORS) {
+			handle_error();
+			continue;
+		}
+	} while (!(status & SCI_RD_F));
+	c = ctrl_inb(SC_RDR);
+	ctrl_out(SCI_RDRF_CLEAR, SC_SR);
+	restore_flags(flags);
+
+	return c;
+}
+
+/* Taken from sh-stub.c of GDB 4.18 */
+static const char hexchars[] = "0123456789abcdef";
+static char highhex(int  x)
+{
+	return hexchars[(x >> 4) & 0xf];
+}
+
+static char lowhex(int  x)
+{
+	return hexchars[x & 0xf];
+}
+
+static void gdb_detach(void)
+{
+	asm volatile("trapa	#0xff");
+
+	if (in_gdb == 1) {
+		in_gdb = 0;
+		get_char();
+		put_char('\r');
+		put_char('\n');
+	}
+}
+#endif
+
+/* send the packet in buffer.  The host get's one chance to read it.
+   This routine does not wait for a positive acknowledge.  */
+
+static void
+put_string(const char *buffer, int count)
+{
+	int i;
+	const unsigned char *p = buffer;
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+	int checksum;
+
+if (in_gdb) {
+	/*  $<packet info>#<checksum>. */
+	do {
+		unsigned char c;
+		put_char('$');
+		put_char('O'); /* 'O'utput to console */
+		checksum = 'O';
+
+		for (i=0; i<count; i++) { /* Don't use run length encoding */
+			int h, l;
+
+			c = *p++;
+			h = highhex(c);
+			l = lowhex(c);
+			put_char(h);
+			put_char(l);
+			checksum += h + l;
+		}
+		put_char('#');
+		put_char(highhex(checksum));
+		put_char(lowhex(checksum));
+	} while  (get_char() != '+');
+} else
+#endif
+	for (i=0; i<count; i++) {
+		if (*p == 10)
+			put_char('\r');
+		put_char(*p++);
+	}
+}
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+				 unsigned count)
+{
+	put_string(s, count);
+}
+
+/*
+ *	Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+	/* Not implemented yet */
+	return 0;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, SCI_MINOR_START + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity. We do two things here:
+ *	- construct a cflag setting for the first rs_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+static int __init serial_console_setup(struct console *co, char *options)
+{
+	int	baud = 115200;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	char	*s;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch (baud) {
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			break;
+	}
+	switch (bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch (parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	/* XXX: set baud, char, and parity here. */
+	return 0;
+}
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *	Register console.
+ */
+
+void __init serial_console_init(void)
+{
+	register_console(&sercons);
+}
+#endif /* CONFIG_SERIAL_CONSOLE */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h
--- v2.3.49/linux/drivers/char/sh-sci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sh-sci.h	Tue Mar  7 11:10:03 2000
@@ -0,0 +1,196 @@
+/* $Id: sh-sci.h,v 1.5 2000-03-05 13:54:32+09 gniibe Exp $
+ *
+ *  linux/drivers/char/sh-sci.h
+ *
+ *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+ *  Copyright (C) 1999, 2000  Niibe Yutaka
+ *  Copyright (C) 2000  Greg Banks
+ *
+ */
+#include <linux/config.h>
+
+#if defined(CONFIG_SH_SCI_SERIAL)
+#if defined(__sh3__)
+#define SCSMR  (volatile unsigned char *)0xfffffe80
+#define SCBRR  0xfffffe82
+#define SCSCR  (volatile unsigned char *)0xfffffe84
+#define SC_TDR  0xfffffe86
+#define SC_SR  (volatile unsigned char *)0xfffffe88
+#define SC_RDR  0xfffffe8a
+#define SCSPTR 0xffffff7c
+
+#define SCSCR_INIT	0x30	/* TIE=0,RIE=0,TE=1,RE=1 */
+
+#elif defined(__SH4__)
+Not yet.
+#endif
+
+#define SCI_TD_E  0x80
+#define SCI_RD_F  0x40
+#define SCI_ORER  0x20
+#define SCI_FER   0x10
+#define SCI_PER   0x08
+#define SCI_TEND  0x04
+
+#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
+#define SCI_TD_E_CLEAR		0x78
+#define SCI_RDRF_CLEAR		0xbc
+#define SCI_ERROR_CLEAR		0xc4
+
+#define SCI_CTRL_FLAGS_TIE  0x80
+#define SCI_CTRL_FLAGS_RIE  0x40
+#define SCI_CTRL_FLAGS_TE   0x20
+#define SCI_CTRL_FLAGS_RE   0x10
+/* TEIE=0x04 */
+#define SCI_CTRL_FLAGS_CKE1 0x02
+#define SCI_CTRL_FLAGS_CKE0 0x01
+
+#define RFCR    0xffffff74
+
+#define SCI_ERI_IRQ	23
+#define SCI_RXI_IRQ	24
+#define SCI_TXI_IRQ	25
+#define SCI_TEI_IRQ	26
+#define SCI_IRQ_END	27
+
+#define SCI_IPR_OFFSET	(16+4)
+#endif
+
+#if defined(CONFIG_SH_SCIF_SERIAL)
+#if defined(__sh3__)
+#define SCSMR  (volatile unsigned char *)0xA4000150
+#define SCBRR  0xA4000152
+#define SCSCR  (volatile unsigned char *)0xA4000154
+#define SC_TDR 0xA4000156
+#define SC_SR  (volatile unsigned short *)0xA4000158
+#define SC_RDR 0xA400015A
+#define SCFCR  (volatile unsigned char *)0xA400015C
+#define SCFDR  0xA400015E
+#undef  SCSPTR /* Is there any register for RTS?? */
+#undef  SCLSR
+
+#define RFCR   0xffffff74
+
+#define SCSCR_INIT	0x30	/* TIE=0,RIE=0,TE=1,RE=1 */
+				/* 0x33 when external clock is used */
+#define SCI_IPR_OFFSET	(64+4)
+
+#elif defined(__SH4__)
+#define SCSMR  (volatile unsigned short *)0xFFE80000
+#define SCBRR  0xFFE80004
+#define SCSCR  (volatile unsigned short *)0xFFE80008
+#define SC_TDR 0xFFE8000C
+#define SC_SR  (volatile unsigned short *)0xFFE80010
+#define SC_RDR 0xFFE80014
+#define SCFCR  (volatile unsigned short *)0xFFE80018
+#define SCFDR  0xFFE8001C
+#define SCSPTR 0xFFE80020
+#define SCLSR  0xFFE80024
+
+#define RFCR   0xFF800028
+
+#define SCSCR_INIT	0x0038	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+#define SCI_IPR_OFFSET	(32+4)
+
+#endif
+
+#define SCI_ER    0x0080
+#define SCI_TEND  0x0040
+#define SCI_TD_E  0x0020
+#define SCI_BRK   0x0010
+#define SCI_FER   0x0008
+#define SCI_PER   0x0004
+#define SCI_RD_F  0x0002
+#define SCI_DR    0x0001
+
+#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ER | SCI_BRK)
+#define SCI_TD_E_CLEAR		0x00df
+#define SCI_TEND_CLEAR		0x00bf
+#define SCI_RDRF_CLEAR		0x00fc
+#define SCI_ERROR_CLEAR		0x0063
+
+#define SCI_CTRL_FLAGS_TIE  0x80
+#define SCI_CTRL_FLAGS_RIE  0x40
+#define SCI_CTRL_FLAGS_TE   0x20
+#define SCI_CTRL_FLAGS_RE   0x10
+#define SCI_CTRL_FLAGS_REIE 0x08
+#define SCI_CTRL_FLAGS_CKE1 0x02
+
+#if defined(__sh3__)
+#define SCI_ERI_IRQ	56
+#define SCI_RXI_IRQ	57
+#define SCI_BRI_IRQ	58
+#define SCI_TXI_IRQ	59
+#define SCI_IRQ_END	60
+#elif defined(__SH4__)
+#define SCI_ERI_IRQ	40
+#define SCI_RXI_IRQ	41
+#define SCI_BRI_IRQ	42
+#define SCI_TXI_IRQ	43
+#define SCI_IRQ_END	44
+#endif
+#endif
+
+#define SCI_PRIORITY	3
+
+#define SCI_MINOR_START		64
+#define SCI_RX_THROTTLE		0x0000001
+
+#define O_OTHER(tty)    \
+      ((O_OLCUC(tty))  ||\
+      (O_ONLCR(tty))   ||\
+      (O_OCRNL(tty))   ||\
+      (O_ONOCR(tty))   ||\
+      (O_ONLRET(tty))  ||\
+      (O_OFILL(tty))   ||\
+      (O_OFDEL(tty))   ||\
+      (O_NLDLY(tty))   ||\
+      (O_CRDLY(tty))   ||\
+      (O_TABDLY(tty))  ||\
+      (O_BSDLY(tty))   ||\
+      (O_VTDLY(tty))   ||\
+      (O_FFDLY(tty)))
+
+#define I_OTHER(tty)    \
+      ((I_INLCR(tty))  ||\
+      (I_IGNCR(tty))   ||\
+      (I_ICRNL(tty))   ||\
+      (I_IUCLC(tty))   ||\
+      (L_ISIG(tty)))
+
+#define SCI_MAGIC 0xbabeface
+
+struct sci_port {
+	struct gs_port gs;
+	unsigned int old_cflag;
+};
+
+#define WAIT_RFCR_COUNTER 200
+
+/*
+ * Values for the BitRate Register (SCBRR)
+ *
+ * The values are actually divisors for a frequency which can
+ * be internal to the SH3 (14.7456MHz) or derived from an external
+ * clock source.  This driver assumes the internal clock is used;
+ * to support using an external clock source, config options or
+ * possibly command-line options would need to be added.
+ *
+ * Also, to support speeds below 2400 (why?) the lower 2 bits of
+ * the SCSMR register would also need to be set to non-zero values.
+ *
+ * -- Greg Banks 27Feb2000
+ */
+
+#if defined(__sh3__)
+#define BPS_2400       191
+#define BPS_4800       95
+#define BPS_9600       47
+#define BPS_19200      23
+#define BPS_38400      11
+#define BPS_115200     3
+#elif defined(__SH4__)
+/* Values for SH-4 please! */
+
+#define BPS_115200     8
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/char/stradis.c linux/drivers/char/stradis.c
--- v2.3.49/linux/drivers/char/stradis.c	Tue Jan 11 22:31:40 2000
+++ linux/drivers/char/stradis.c	Fri Mar  3 12:54:45 2000
@@ -28,6 +28,7 @@
 #include <linux/major.h>
 #include <linux/malloc.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
@@ -2236,13 +2237,9 @@
 	}
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-#else
-int init_stradis_cards(struct video_init *unused)
+
+static int __init stradis_init (void)
 {
-#endif
 	struct pci_dev *dev = NULL;
 	int result = 0, i;
 
@@ -2269,11 +2266,14 @@
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+
+static void __exit stradis_exit (void)
 {
 	release_saa();
 	printk(KERN_INFO "stradis: module cleanup complete\n");
 }
 
-#endif
+
+module_init(stradis_init);
+module_exit(stradis_exit);
+
diff -u --recursive --new-file v2.3.49/linux/drivers/char/tda9855.c linux/drivers/char/tda9855.c
--- v2.3.49/linux/drivers/char/tda9855.c	Tue Jan 11 22:31:40 2000
+++ linux/drivers/char/tda9855.c	Wed Dec 31 16:00:00 1969
@@ -1,455 +0,0 @@
-/*
- * For the TDA9855 chip (afaik, only the Diamond DTV2000 has this)
- * This driver will not complain if used with a TDA9850 or any 
- * other i2c device with the same address.
- *
- * Copyright (c) 1999 Steve VanDeBogart (vandebo@uclink.berkeley.edu)
- * This code is placed under the terms of the GNU General Public License
- * Based on tda8425.c by Greg Alexander (c) 1998
- *
- * TODO:
- *   Fix channel change bug - sound goes out when changeing channels, mute
- *                            and unmote to fix.
- *   Fine tune sound
- *   Get rest of capabilities into video_audio struct...
- *
- *  Revision: 0.1 
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-
-/* Addresses to scan */
-#define I2C_TDA9855_L        0xb4
-#define I2C_TDA9855_H        0xb6
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {
-    I2C_TDA9855_L >> 1,
-    I2C_TDA9855_H >> 1,
-    I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
-
-struct tda9855 {
-	int addr;
-	int rvol, lvol;
-	int bass, treble, sub;
-	int c1, c2, c3;
-	int a1, a2, a3;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-
-#define dprintk  if (debug) printk
-
-                                 /* subaddresses */
-#define TDA9855_VR	0x00 /* Volume, right */
-#define TDA9855_VL	0x01 /* Volume, left */
-#define TDA9855_BA	0x02 /* Bass */
-#define TDA9855_TR	0x03 /* Treble */
-#define TDA9855_SW	0x04 /* Subwoofer - not connected on DTV2000 */
-#define TDA9855_C1	0x05 /* Control 1 */
-#define TDA9855_C2	0x06 /* Control 2 */
-#define TDA9855_C3	0x07 /* Control 3 */
-#define TDA9855_A1	0x08 /* Alignmnet 1*/
-#define TDA9855_A2	0x09 /* Alignmnet 2*/
-#define TDA9855_A3	0x0a /* Alignmnet 3*/
-				 /* Masks for bits in subaddresses */
-/* VR */ /* VL */
-/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
- * in 1dB steps - mute is 0x27 */
-
-/* BA */ 
-/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
- * in .5dB steps - 0 is 0x0E */
-
-/* TR */
-/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
- * in 3dB steps - 0 is 0x7 */
-
-/* SW */
-/* 4 bits << 2 control subwoofer/surraound gain from -14db (0x1) to 14db (0xf)
- * in 3dB steps - mute is 0x0 */
-
-/* C1 */
-#define TDA9855_MUTE	1<<7 /* GMU, Mute at outputs */
-#define TDA9855_AVL	1<<6 /* AVL, Automatic Volume Level */
-#define TDA9855_LOUD	1<<5 /* Loudness, 1==off */
-#define TDA9855_SUR	1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
-				/* Bits 0 to 3 select various combinations
-                                 * of line in and line out, only the 
-                                 * interesting ones are defined */
-#define TDA9855_EXT	1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
-#define TDA9855_INT	0    /* Selects inputs LOR and LOL.  (internal) */
-
-/* C2 */
-#define TDA9855_SAP	3<<6 /* Selects SAP output, mute if not received */
-#define TDA9855_STEREO	1<<6 /* Selects Stereo ouput, mono if not received */
-#define TDA9855_MONO	0    /* Forces Mono output */
-#define TDA9855_TZCM	1<<5 /* If set, don't mute till zero crossing */
-#define TDA9855_VZCM	1<<4 /* If set, don't change volume till zero crossing*/
-#define TDA9855_LMU	1<<3 /* Mute at LOR and LOL */
-#define TDA9855_LINEAR	0    /* Linear Stereo */
-#define TDA9855_PSEUDO	1    /* Pseudo Stereo */
-#define TDA9855_SPAT_30	2    /* Spatial Stereo, 30% anti-phase crosstalk */
-#define TDA9855_SPAT_50	3    /* Spatial Stereo, 52% anti-phase crosstalk */
-#define TDA9855_E_MONO	7    /* Forced mono - mono select elseware, so useless*/
-
-/* C3 */
-/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
- * in .5dB steps -  0 is 0x7 */
-
-/* A1 and A2 (read/write) */
-/* lower 5 bites are wideband and spectral expander alignment
- * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
-#define TDA9855_STP	1<<5 /* Stereo Pilot/detect (read-only) */
-#define TDA9855_SAPP	1<<6 /* SAP Pilot/detect (read-only) */
-#define TDA9855_STS	1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
-
-/* A3 */
-/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
- * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
-/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), 
- * 1200ohm (0x1), 2100ohm (0x3) */
-#define TDA9855_ADJ	1<<7 /* Stereo adjust on/off (wideband and spectral) */
-
-
-/* Begin code */
-
-static int tda9855_write(struct i2c_client *client, int subaddr, int val)
-{
-	unsigned char buffer[2];
-	
-	buffer[0] = subaddr;
-	buffer[1] = val;
-	if (2 != i2c_master_send(client,buffer,2)) {
-		printk(KERN_WARNING "tda9855: I/O error, trying (write %d 0x%x)\n",
-		       subaddr, val);
-		return -1;
-	}
-	return 0;
-}
-
-static int tda9855_read(struct i2c_client *client)
-{
-	unsigned char buffer;
-	
-	if (1 != i2c_master_recv(client,&buffer,1)) {
-		printk(KERN_WARNING "tda9855: I/O error, trying (read)\n");
-		return -1;
-	}
-	return buffer;
-}
-
-static int tda9855_set(struct i2c_client *client)
-{
-	struct tda9855 *t = client->data;
-	unsigned char buf[16];
-	
-	dprintk(KERN_INFO "tda9855_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",t->rvol,t->lvol,t->bass,t->treble,t->sub,
-		t->c1,t->c2,t->c3,t->a1,t->a2,t->a3);
-	buf[0]  = TDA9855_VR;
-	buf[1]  = t->rvol;
-	buf[2]  = t->lvol;
-	buf[3]  = t->bass;
-	buf[4]  = t->treble;
-	buf[5]  = t->sub;
-	buf[6]  = t->c1;
-	buf[7]  = t->c2;
-	buf[8]  = t->c3;
-	buf[9]  = t->a1;
-	buf[10] = t->a2;
-	buf[11] = t->a3;
-	if (12 != i2c_master_send(client,buf,12)) {
-		printk(KERN_WARNING "tda9855: I/O error, trying tda9855_set\n");
-		return -1;
-	}
-	return 0;
-}
-
-static void do_tda9855_init(struct i2c_client *client)
-{
-	struct tda9855 *t = client->data;
-
-	t->rvol=0x6f;         /* 0dB */
-	t->lvol=0x6f;		/* 0dB */
-	t->bass=0x0e;         /* 0dB */
-	t->treble=(0x07 << 1);  /* 0dB */
-	t->sub=0x8 << 2;      /* 0dB */
-	t->c1=TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT;  
-	/* Set Mute, AVL, Loudness off, Internal sound */
-	t->c2=TDA9855_STEREO | TDA9855_LINEAR; /* Set Stereo liner mode */
-	t->c3=0x07;           /* 0dB input gain */
-	t->a1=0x10;	 	/* Select nominal wideband expander */
-	t->a2=0x10;		/* Select nominal spectral expander and 30mV trigger */
-	t->a3=0x3;            /* Set: nominal timinig current, 420ohm AVL attack */
-	tda9855_write(client, TDA9855_C1, TDA9855_MUTE); /* mute */
-	tda9855_set(client);
-}
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda9855_attach(struct i2c_adapter *adap, int addr,
-			  unsigned short flags, int kind)
-{
-	struct tda9855 *t;
-	struct i2c_client *client;
-
-	client = kmalloc(sizeof *client,GFP_KERNEL);
-	if (!client)
-		return -ENOMEM;		
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
-	
-	client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
-	if (!t)
-		return -ENOMEM;
-	memset(t,0,sizeof *t);
-	do_tda9855_init(client);
-	MOD_INC_USE_COUNT;
-	strcpy(client->name,"TDA9855");
-	printk(KERN_INFO "tda9855: init\n");
-
-	i2c_attach_client(client);
-	return 0;
-}
-
-static int tda9855_probe(struct i2c_adapter *adap)
-{
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-		return i2c_probe(adap, &addr_data, tda9855_attach);
-	return 0;
-}
-
-static int tda9855_detach(struct i2c_client *client)
-{
-	struct tda9855 *t  = client->data;
-
-	do_tda9855_init(client);
-	i2c_detach_client(client);
-	
-	kfree(t);
-	kfree(client);
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-static int tda9855_command(struct i2c_client *client,
-			   unsigned int cmd, void *arg)
-{
-	struct tda9855 *t = client->data;
-#if 0
-	__u16 *sarg = arg;
-#endif
-
-	switch (cmd) {
-	/* --- v4l ioctls --- */
-	/* take care: bttv does userspace copying, we'll get a
-	   kernel pointer here... */
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *va = arg;
-		int left,right;
-
-		va->flags |= VIDEO_AUDIO_VOLUME |
-			VIDEO_AUDIO_BASS |
-			VIDEO_AUDIO_TREBLE;
-
-		/* min is 0x27 max is 0x7f, vstep is 2e8 */
-		left = (t->lvol-0x27)*0x2e8;
-		right = (t->rvol-0x27)*0x2e8;
-		va->volume=MAX(left,right);
-		va->balance=(32768*MIN(left,right))/
-			(va->volume ? va->volume : 1);
-		va->balance=(left<right)?
-			(65535-va->balance) : va->balance;
-		va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */
-		va->treble = ((t->treble>>1)-0x3)*0x1c71;
-
-		va->mode = ((TDA9855_STP | TDA9855_SAPP) & 
-			    tda9855_read(client)) >> 4;
-		va->mode |= VIDEO_SOUND_MONO;
-		break;
-	}
-	case VIDIOCSAUDIO:
-	{
-		struct video_audio *va = arg;
-		int left,right;
-
-		left = (MIN(65536 - va->balance,32768) *
-			va->volume) / 32768;
-		right = (MIN(va->balance,32768) *
-			 va->volume) / 32768;
-		t->lvol = left/0x2e8+0x27;
-		t->rvol = right/0x2e8+0x27;
-		t->bass = va->bass/0xccc+0x6;
-		t->treble = (va->treble/0x1c71+0x3)<<1;
-		tda9855_write(client,TDA9855_VL,t->lvol);
-		tda9855_write(client,TDA9855_VR,t->rvol);
-		tda9855_write(client,TDA9855_BA, t->bass);
-		tda9855_write(client,TDA9855_TR,t->treble);
-
-		switch (va->mode) {
-		case VIDEO_SOUND_MONO:
-			t->c2= TDA9855_MONO | (t->c2 & 0x3f);
-			break;
-		case VIDEO_SOUND_STEREO:
-			t->c2= TDA9855_STEREO | (t->c2 & 0x3f); 
-			break;
-		case VIDEO_SOUND_LANG1:
-			t->c2= TDA9855_SAP | (t->c2 & 0x3f); 
-			break;
-		}
-		tda9855_write(client,TDA9855_C2,t->c2);
-		break;
-	}
-
-#if 0
-	/* --- old, obsolete interface --- */
-	case AUDC_GET_VOLUME_LEFT:
-		*sarg = (t->lvol-0x27)*0x2e8; /* min is 0x27 max is 0x7f, vstep is 2e8 */
-		break;
-	case AUDC_GET_VOLUME_RIGHT:
-		*sarg = (t->rvol-0x27)*0x2e8;
-		break;
-	case AUDC_SET_VOLUME_LEFT:
-		t->lvol = *sarg/0x2e8+0x27;
-		break;
-	case AUDC_SET_VOLUME_RIGHT:
-		t->rvol = *sarg/0x2e8+0x27;
-		break;
-	case AUDC_GET_BASS:
-		*sarg = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */
-		break;
-	case AUDC_SET_BASS:
-		t->bass = *sarg/0xccc+0x6;
-		tda9855_write(client,TDA9855_BA, t->bass);
-		break;
-	case AUDC_GET_TREBLE:
-		*sarg = ((t->treble>>1)-0x3)*0x1c71;
-		break;
-	case AUDC_SET_TREBLE:
-		t->treble = (*sarg/0x1c71+0x3)<<1;
-		tda9855_write(client,TDA9855_TR,t->treble);
-		break;
-	case AUDC_GET_STEREO:
-		*sarg = ((TDA9855_STP | TDA9855_SAPP) & 
-			 tda9855_read(client)) >> 4;
-		if(*sarg==0) *sarg=VIDEO_SOUND_MONO;
-		break;
-	case AUDC_SET_STEREO:
-		if(*sarg==VIDEO_SOUND_MONO)
-			t->c2= TDA9855_MONO | (t->c2 & 0x3f); 
-		/* Mask out the sap and stereo bits and set mono */
-		else if(*sarg==VIDEO_SOUND_STEREO)
-			t->c2= TDA9855_STEREO | (t->c2 & 0x3f); 
-		/* Mask out the sap and stereo bits and set stereo */
-		else if(*sarg==VIDEO_SOUND_LANG2)
-			t->c2= TDA9855_SAP | (t->c2 & 0x3f); 
-		/* Mask out the sap and stereo bits and set sap */
-		tda9855_write(client,TDA9855_C2,t->c2);
-		break;
-	case AUDC_SET_INPUT:
-		dprintk(KERN_INFO "tda9855: SET_INPUT with 0x%04x\n",*sarg);
-		if((*sarg & (AUDIO_MUTE | AUDIO_OFF))!=0)
-			t->c1|=TDA9855_MUTE;
-		else
-			t->c1= t->c1 & 0x7f;  /* won't work -->  (~TDA9855_MUTE); */
-		if((*sarg & AUDIO_INTERN) == AUDIO_INTERN)
-			t->c1=(t->c1 & ~0x7) | TDA9855_INT;  /* 0x7 is a mask for the int/ext */
-		if((*sarg & AUDIO_EXTERN) == AUDIO_EXTERN)
-			t->c1=(t->c1 & ~0x7) | TDA9855_EXT;  /* 0x7 is a mask for the int/ext */
-		tda9855_write(client,TDA9855_C1,t->c1);
-		break;
-    case AUDC_SWITCH_MUTE:
-	    if((t->c1 & ~TDA9855_MUTE) == 0)
-		    t->c1|=TDA9855_MUTE;
-	    else
-		    t->c1&=~TDA9855_MUTE;
-	    tda9855_write(client,TDA9855_C1,t->c1);
-	    break;
-	    
-/* TDA9855 unsupported: */
-/*	case AUDC_NEWCHANNEL:
-	case AUDC_SET_RADIO:
-	case AUDC_GET_DC:
-*/
-#endif
-	default:
-		/* nothing */
-	}
-	return 0;
-}
-
-
-static struct i2c_driver driver = {
-        "i2c tda9855 driver",
-        I2C_DRIVERID_TDA9855,
-        I2C_DF_NOTIFY,
-	tda9855_probe,
-        tda9855_detach,
-        tda9855_command,
-};
-
-static struct i2c_client client_template =
-{
-        "(unset)",		/* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tda9855_init(void)
-#endif
-{
-	i2c_add_driver(&driver);
-	return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-	i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/tda985x.c linux/drivers/char/tda985x.c
--- v2.3.49/linux/drivers/char/tda985x.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/tda985x.c	Mon Mar  6 15:32:30 2000
@@ -0,0 +1,532 @@
+/*
+ * For the TDA9850 and TDA9855 chips
+ * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used 
+ * on STB cards.  Other cards probably use these chips as well.)
+ * This driver will not complain if used with any 
+ * other i2c device with the same address.
+ *
+ * Copyright (c) 1999 Gerd Knorr
+ * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) 
+ * This code is placed under the terms of the GNU General Public License
+ * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ * Which was based on tda8425.c by Greg Alexander (c) 1998
+ *
+ * OPTIONS:
+ * debug   - set to 1 if you'd like to see debug messages
+ * chip    - set to 9850 or 9855 to select your chip (default 9855)
+ *
+ * TODO:
+ *   Fix channel change bug - sound goes out when changeing channels, mute
+ *                            and unmote to fix. - Is this still here?
+ *   Fine tune sound
+ *   Get rest of capabilities into video_audio struct...
+ * 
+ *  Revision: 0.4 - check for correct chip= insmod value
+ *                  also cleaned up comments a bit
+ *  Revision: 0.3 - took out extraneous tda985x_write in tda985x_command
+ *  Revision: 0.2 - added insmod option chip=
+ *  Revision: 0.1 - original version
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bttv.h"
+#include "audiochip.h"
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(chip,"i");
+MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855");
+
+static int debug = 0;	/* insmod parameter */
+static int chip = 9855;	/* insmod parameter */
+
+/* Addresses to scan */
+#define I2C_TDA985x_L        0xb4
+#define I2C_TDA985x_H        0xb6
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {
+    I2C_TDA985x_L >> 1,
+    I2C_TDA985x_H >> 1,
+    I2C_CLIENT_END};
+static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+	normal_i2c, normal_i2c_range, 
+	probe, probe_range, 
+	ignore, ignore_range, 
+	force
+};
+
+/* This is a superset of the TDA9850 and TDA9855 members */
+
+struct tda985x {
+	int addr;
+	int rvol, lvol;
+	int bass, treble, sub;
+	int c4, c5, c6, c7;
+	int a1, a2, a3;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+#define dprintk  if (debug) printk
+
+/* The TDA9850 and TDA9855 are both made by Philips Semiconductor
+ * http://www.semiconductors.philips.com
+ * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder
+ * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor
+ *
+ * The TDA9850 has more or less a subset of the functions that the TDA9855
+ * has.  As a result, we can re-use many of these defines.  Anything with
+ * TDA9855 is specific to that chip, anything with TDA9850 is specific
+ * to that chip, and anything with TDA985x is valid for either.
+ *
+ * To complicate things further, the TDA9850 uses labels C1 through C4
+ * for subaddresses 0x04 through 0x07, while the TDA9855 uses
+ * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing.
+ * To help keep things straight, I have renamed the various C[1,4] labels
+ * to C[4,7] so that the numerical label matches the hex value of the
+ * subaddress for both chips.  At least the A[1,3] labels line up.  :)
+ */ 
+
+		/* subaddresses for TDA9855 */
+#define TDA9855_VR	0x00 /* Volume, right */
+#define TDA9855_VL	0x01 /* Volume, left */
+#define TDA9855_BA	0x02 /* Bass */
+#define TDA9855_TR	0x03 /* Treble */
+#define TDA9855_SW	0x04 /* Subwoofer - not connected on DTV2000 */
+
+		/* subaddresses for TDA9850 */
+#define TDA9850_C4	0x04 /* Control 1 for TDA9850 */
+
+		/* subaddesses for both chips */
+#define TDA985x_C5	0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
+#define TDA985x_C6	0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
+#define TDA985x_C7	0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
+#define TDA985x_A1	0x08 /* Alignment 1 for both chips */
+#define TDA985x_A2	0x09 /* Alignment 2 for both chips */
+#define TDA985x_A3	0x0a /* Alignment 3 for both chips */
+
+		/* Masks for bits in TDA9855 subaddresses */
+/* 0x00 - VR in TDA9855 */
+/* 0x01 - VL in TDA9855 */
+/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
+ * in 1dB steps - mute is 0x27 */
+
+
+/* 0x02 - BA in TDA9855 */ 
+/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
+ * in .5dB steps - 0 is 0x0E */
+
+
+/* 0x03 - TR in TDA9855 */
+/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
+ * in 3dB steps - 0 is 0x7 */
+
+		/* Masks for bits in both chips' subaddresses */
+/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
+/* Unique to TDA9855: */
+/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
+ * in 3dB steps - mute is 0x0 */
+ 
+/* Unique to TDA9850: */
+/* lower 4 bits control stereo noise threshold, over which stereo turns off
+ * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
+
+
+/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
+/* Unique to TDA9855: */
+#define TDA9855_MUTE	1<<7 /* GMU, Mute at outputs */
+#define TDA9855_AVL	1<<6 /* AVL, Automatic Volume Level */
+#define TDA9855_LOUD	1<<5 /* Loudness, 1==off */
+#define TDA9855_SUR	1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
+				/* Bits 0 to 3 select various combinations
+                                 * of line in and line out, only the 
+                                 * interesting ones are defined */
+#define TDA9855_EXT	1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
+#define TDA9855_INT	0    /* Selects inputs LOR and LOL.  (internal) */
+
+/* Unique to TDA9850:  */
+/* lower 4 bits contol SAP noise threshold, over which SAP turns off
+ * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
+
+
+/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
+/* Common to TDA9855 and TDA9850: */
+#define TDA985x_SAP	3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_STEREO	1<<6 /* Selects Stereo ouput, mono if not received */
+#define TDA985x_MONO	0    /* Forces Mono output */
+#define TDA985x_LMU	1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
+
+/* Unique to TDA9855: */
+#define TDA9855_TZCM	1<<5 /* If set, don't mute till zero crossing */
+#define TDA9855_VZCM	1<<4 /* If set, don't change volume till zero crossing*/
+#define TDA9855_LINEAR	0    /* Linear Stereo */
+#define TDA9855_PSEUDO	1    /* Pseudo Stereo */
+#define TDA9855_SPAT_30	2    /* Spatial Stereo, 30% anti-phase crosstalk */
+#define TDA9855_SPAT_50	3    /* Spatial Stereo, 52% anti-phase crosstalk */
+#define TDA9855_E_MONO	7    /* Forced mono - mono select elseware, so useless*/
+
+
+/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
+ * in .5dB steps -  0dB is 0x7 */
+
+
+/* 0x08, 0x09 - A1 and A2 (read/write) */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 5 bites are wideband and spectral expander alignment
+ * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
+#define TDA985x_STP	1<<5 /* Stereo Pilot/detect (read-only) */
+#define TDA985x_SAPP	1<<6 /* SAP Pilot/detect (read-only) */
+#define TDA985x_STS	1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
+
+
+/* 0x0a - A3 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
+ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
+#define TDA985x_ADJ	1<<7 /* Stereo adjust on/off (wideband and spectral */
+
+/* Unique to TDA9855: */
+/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), 
+ * 1200ohm (0x1), 2100ohm (0x3) */
+
+
+/* Begin code */
+
+static int tda985x_write(struct i2c_client *client, int subaddr, int val)
+{
+	unsigned char buffer[2];
+	dprintk("In tda985x_write\n");
+	dprintk("Writing %d 0x%x\n", subaddr, val);
+	buffer[0] = subaddr;
+	buffer[1] = val;
+	if (2 != i2c_master_send(client,buffer,2)) {
+		printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n",
+		       subaddr, val);
+		return -1;
+	}
+	return 0;
+}
+
+static int tda985x_read(struct i2c_client *client)
+{
+	unsigned char buffer;
+	dprintk("In tda985x_read\n");
+	if (1 != i2c_master_recv(client,&buffer,1)) {
+		printk(KERN_WARNING "tda985x: I/O error, trying (read)\n");
+		return -1;
+	}
+	dprintk("Read 0x%02x\n", buffer); 
+	return buffer;
+}
+
+static int tda985x_set(struct i2c_client *client)
+{
+	struct tda985x *t = client->data;
+	unsigned char buf[16];
+	dprintk("In tda985x_set\n");
+	
+	if (chip == 9855)
+	{
+		dprintk(KERN_INFO 
+			"tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+			t->rvol,t->lvol,t->bass,t->treble,t->sub,
+			t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
+		buf[0]  = TDA9855_VR;
+		buf[1]  = t->rvol;
+		buf[2]  = t->lvol;
+		buf[3]  = t->bass;
+		buf[4]  = t->treble;
+		buf[5]  = t->sub;
+		buf[6]  = t->c5;
+		buf[7]  = t->c6;
+		buf[8]  = t->c7;
+		buf[9]  = t->a1;
+		buf[10] = t->a2;
+		buf[11] = t->a3;
+		if (12 != i2c_master_send(client,buf,12)) {
+			printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n");
+			return -1;
+		}
+	}
+
+	else if (chip == 9850)
+	{
+        	dprintk(KERN_INFO 
+			"tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+	               	 t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
+		buf[0]  = TDA9850_C4;
+		buf[1]  = t->c4;
+		buf[2]  = t->c5;
+		buf[3]  = t->c6;
+		buf[4]  = t->c7;
+		buf[5]  = t->a1;
+		buf[6]  = t->a2;
+		buf[7]  = t->a3;
+		if (8 != i2c_master_send(client,buf,8)) {
+			printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n");
+			return -1;
+	        }
+	}
+
+	return 0;
+}
+
+static void do_tda985x_init(struct i2c_client *client)
+{
+	struct tda985x *t = client->data;
+	dprintk("In tda985x_init\n");
+
+	if (chip == 9855)
+	{
+		printk("Using tda9855 options\n");
+		t->rvol = 0x6f;		/* 0dB */
+		t->lvol = 0x6f;		/* 0dB */
+		t->bass = 0x0e;		/* 0dB */
+		t->treble = (0x07 << 1);	/* 0dB */
+		t->sub = 0x8 << 2;	/* 0dB */
+		t->c5 = TDA9855_MUTE | TDA9855_AVL | 
+			TDA9855_LOUD | TDA9855_INT;  
+		/* Set Mute, AVL, Loudness off, Internal sound */
+		t->c6 = TDA985x_STEREO | TDA9855_LINEAR |
+			TDA9855_TZCM | TDA9855_VZCM;
+		/* Stereo linear mode, also wait til zero crossings  */
+		t->c7 = 0x07;		/* 0dB input gain */
+	}
+
+	else if (chip == 9850)
+	{
+		printk("Using tda9850 options\n");
+		t->c4 = 0x08;		/* Set stereo noise thresh to nominal */
+		t->c5 = 0x08;		/* Set SAP noise threshold to nominal */
+		t->c6 = TDA985x_STEREO;	/* Select Stereo mode for decoder */
+		t->c7 = 0x07;		/* 0dB input gain */
+	}
+
+	/* The following is valid for both chip types */	
+	t->a1 = 0x10;	/* Select nominal wideband expander */
+	t->a2 = 0x10;	/* Select nominal spectral expander and 30mV trigger */
+	t->a3 = 0x3;	/* Set: nominal timing current, 420ohm AVL attack */
+
+	tda985x_set(client);
+}
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda985x_attach(struct i2c_adapter *adap, int addr,
+			  unsigned short flags, int kind)
+{
+	struct tda985x *t;
+	struct i2c_client *client;
+	dprintk("In tda985x_attach\n");
+	client = kmalloc(sizeof *client,GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;		
+        memcpy(client,&client_template,sizeof(struct i2c_client));
+        client->adapter = adap;
+        client->addr = addr;
+	
+	client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
+	if (!t)
+		return -ENOMEM;
+	memset(t,0,sizeof *t);
+	do_tda985x_init(client);
+	MOD_INC_USE_COUNT;
+	strcpy(client->name,"TDA985x");
+	printk(KERN_INFO "tda985x: init\n");
+
+	i2c_attach_client(client);
+	return 0;
+}
+
+static int tda985x_probe(struct i2c_adapter *adap)
+{
+	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+		return i2c_probe(adap, &addr_data, tda985x_attach);
+	return 0;
+}
+
+static int tda985x_detach(struct i2c_client *client)
+{
+	struct tda985x *t  = client->data;
+
+	do_tda985x_init(client);
+	i2c_detach_client(client);
+	
+	kfree(t);
+	kfree(client);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int tda985x_command(struct i2c_client *client,
+			   unsigned int cmd, void *arg)
+{
+	struct tda985x *t = client->data;
+	dprintk("In tda985x_command...\n");
+#if 0
+	__u16 *sarg = arg;
+#endif
+
+	switch (cmd) {
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOCGAUDIO:
+	{
+		struct video_audio *va = arg;
+		dprintk("VIDIOCGAUDIO\n");
+		if (chip == 9855)
+		{
+			int left,right;
+
+			va->flags |= VIDEO_AUDIO_VOLUME |
+				VIDEO_AUDIO_BASS |
+				VIDEO_AUDIO_TREBLE;
+
+			/* min is 0x27 max is 0x7f, vstep is 2e8 */
+			left = (t->lvol-0x27)*0x2e8;
+			right = (t->rvol-0x27)*0x2e8;
+			va->volume=MAX(left,right);
+			va->balance=(32768*MIN(left,right))/
+				(va->volume ? va->volume : 1);
+			va->balance=(left<right)?
+				(65535-va->balance) : va->balance;
+			va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */
+			va->treble = ((t->treble>>1)-0x3)*0x1c71;
+		}
+
+		/* Valid for both chips: */
+		{
+			va->mode = ((TDA985x_STP | TDA985x_SAPP) & 
+				    tda985x_read(client)) >> 4;
+			/* Add mono mode regardless of SAP and stereo */
+			/* Allows forced mono */
+			va->mode |= VIDEO_SOUND_MONO;
+		}
+
+		break; /* VIDIOCGAUDIO case */
+	}
+
+	case VIDIOCSAUDIO:
+	{
+		struct video_audio *va = arg;
+		dprintk("VIDEOCSAUDIO...\n");
+		if (chip == 9855)
+		{
+			int left,right;
+
+			left = (MIN(65536 - va->balance,32768) *
+				va->volume) / 32768;
+			right = (MIN(va->balance,32768) *
+				 va->volume) / 32768;
+			t->lvol = left/0x2e8+0x27;
+			t->rvol = right/0x2e8+0x27;
+			t->bass = va->bass/0xccc+0x6;
+			t->treble = (va->treble/0x1c71+0x3)<<1;
+			tda985x_write(client,TDA9855_VL,t->lvol);
+			tda985x_write(client,TDA9855_VR,t->rvol);
+			tda985x_write(client,TDA9855_BA, t->bass);
+			tda985x_write(client,TDA9855_TR,t->treble);
+		}
+
+		/* The following is valid for both chips */
+
+		switch (va->mode) {
+			case VIDEO_SOUND_MONO:
+				dprintk("VIDEO_SOUND_MONO\n");
+				t->c6= TDA985x_MONO | (t->c6 & 0x3f);
+				tda985x_write(client,TDA985x_C6,t->c6);
+				break;
+			case VIDEO_SOUND_STEREO:
+				dprintk("VIDEO_SOUND_STEREO\n");
+				t->c6= TDA985x_STEREO | (t->c6 & 0x3f);
+				tda985x_write(client,TDA985x_C6,t->c6); 
+				break;
+			case VIDEO_SOUND_LANG1:
+				dprintk("VIDEO_SOUND_LANG1\n");
+				t->c6= TDA985x_SAP | (t->c6 & 0x3f);
+				tda985x_write(client,TDA985x_C6,t->c6);
+				break;
+		} /* End of (va->mode) switch */
+		
+		break;
+
+	} /* end of VIDEOCSAUDIO case */
+
+	default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
+
+		/* nothing */
+		dprintk("Default\n");
+
+	} /* end of (cmd) switch */
+
+	return 0;
+}
+
+
+static struct i2c_driver driver = {
+        "i2c tda985x driver",
+        I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */
+        I2C_DF_NOTIFY,
+	tda985x_probe,
+        tda985x_detach,
+        tda985x_command,
+};
+
+static struct i2c_client client_template =
+{
+        "(unset)",		/* name */
+        -1,
+        0,
+        0,
+        NULL,
+        &driver
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int tda985x_init(void)
+#endif
+{
+	if ( (chip != 9850) && (chip != 9855) )
+	{
+		printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n");
+		return -EINVAL;
+	}
+	i2c_add_driver(&driver);
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.49/linux/drivers/char/tty_io.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/tty_io.c	Tue Mar  7 11:07:42 2000
@@ -1321,7 +1321,7 @@
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		minor -= driver->minor_start;
 		devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
-		tty_register_devfs(&pts_driver[major], 0,
+		tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE,
 				   pts_driver[major].minor_start + minor);
 		noctty = 1;
 		goto init_dev_done;
@@ -2003,7 +2003,6 @@
 	struct tty_struct tty;
 	char buf[32];
 
-	flags |= DEVFS_FL_DEFAULT;
 	tty.driver = *driver;
 	tty.device = MKDEV (driver->major, minor);
 	switch (tty.device) {
@@ -2012,28 +2011,22 @@
 			mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 			break;
 		default:
-			flags |= DEVFS_FL_AUTO_OWNER;
 			break;
 	}
-	if ((minor <  driver->minor_start) || 
-	    (minor >= driver->minor_start + driver->num)) {
+	if ( (minor <  driver->minor_start) || 
+	     (minor >= driver->minor_start + driver->num) ) {
 		printk(KERN_ERR "Attempt to register invalid minor number "
 		       "with devfs (%d:%d).\n", (int)driver->major,(int)minor);
 		return;
 	}
-	if (driver->type == TTY_DRIVER_TYPE_CONSOLE) {
-		flags |= DEVFS_FL_AOPEN_NOTIFY;
-		flags &= ~DEVFS_FL_AUTO_OWNER;
-	}
 #  ifdef CONFIG_UNIX98_PTYS
 	if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) &&
 	     (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) {
-		flags &= ~DEVFS_FL_AUTO_OWNER;
 		uid = current->uid;
 		gid = current->gid;
 	}
 #  endif
-	devfs_register (NULL, tty_name (&tty, buf), 0, flags,
+	devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT,
 			driver->major, minor, mode, uid, gid,
 			&tty_fops, NULL);
 #endif /* CONFIG_DEVFS_FS */
diff -u --recursive --new-file v2.3.49/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.3.49/linux/drivers/char/tuner.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/tuner.c	Mon Mar  6 15:32:30 2000
@@ -12,6 +12,7 @@
 #include <linux/videodev.h>
 
 #include "tuner.h"
+#include "audiochip.h"
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
@@ -334,6 +335,9 @@
                         t->type,tuners[t->type].name);
 		strncpy(client->name, tuners[t->type].name, sizeof(client->name));
 		break;
+	case AUDC_SET_RADIO:
+		t->radio = 1;
+		break;
 		
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
@@ -342,6 +346,7 @@
 	{
 		struct video_channel *vc = arg;
 		
+		t->radio = 0;
 		if (t->type == TUNER_PHILIPS_SECAM) {
 			t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0;
 			set_tv_freq(client,t->freq);
diff -u --recursive --new-file v2.3.49/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.3.49/linux/drivers/char/videodev.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/char/videodev.c	Fri Mar  3 12:54:45 2000
@@ -60,9 +60,6 @@
 	{"i2c-tuner", i2c_tuner_init},
 	{"bttv", init_bttv_cards},
 #endif	
-#ifdef CONFIG_VIDEO_STRADIS
-	{"stradis", init_stradis_cards},
-#endif	
 #ifdef CONFIG_VIDEO_BWQCAM
 	{"bw-qcam", init_bw_qcams},
 #endif	
diff -u --recursive --new-file v2.3.49/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- v2.3.49/linux/drivers/isdn/avmb1/b1dma.c	Sat Feb 26 22:31:45 2000
+++ linux/drivers/isdn/avmb1/b1dma.c	Fri Mar  3 12:54:44 2000
@@ -40,7 +40,7 @@
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
-int suppress_pollack = 0;
+static int suppress_pollack = 0;
 MODULE_PARM(suppress_pollack, "0-1i");
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.49/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.3.49/linux/drivers/isdn/avmb1/c4.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/isdn/avmb1/c4.c	Fri Mar  3 12:54:44 2000
@@ -65,7 +65,7 @@
 
 /* ------------------------------------------------------------- */
 
-int suppress_pollack = 0;
+static int suppress_pollack = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
diff -u --recursive --new-file v2.3.49/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.3.49/linux/drivers/net/3c505.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/3c505.c	Fri Mar  3 12:54:44 2000
@@ -1049,7 +1049,6 @@
  
 static void elp_timeout(struct net_device *dev)
 {
-	unsigned long flags;
 	elp_device *adapter = dev->priv;
 	int stat;
 
diff -u --recursive --new-file v2.3.49/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.3.49/linux/drivers/net/3c515.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/3c515.c	Thu Mar  2 22:44:40 2000
@@ -46,6 +46,7 @@
 #define RX_RING_SIZE	16
 #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/isapnp.h>
diff -u --recursive --new-file v2.3.49/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.3.49/linux/drivers/net/3c523.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/3c523.c	Fri Mar  3 12:54:44 2000
@@ -85,10 +85,7 @@
    $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
  */
 
-#ifdef MODULE
 #include <linux/module.h>
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -902,7 +899,7 @@
 #ifndef NO_NOPCOMMANDS
 		if (stat & STAT_CNA) {
 			/* CU went 'not ready' */
-			if (netif_running(dev->state)) {
+			if (netif_running(dev)) {
 				printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status);
 			}
 		}
diff -u --recursive --new-file v2.3.49/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.49/linux/drivers/net/Config.in	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/Config.in	Fri Mar  3 12:56:13 2000
@@ -3,6 +3,7 @@
 #
 
 source drivers/net/arcnet/Config.in
+source drivers/net/appletalk/Config.in
 
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'Bonding driver support' CONFIG_BONDING
@@ -131,9 +132,7 @@
       fi
 
       tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
-      if [ "$CONFIG_OBSOLETE" = "y" ]; then
-         tristate '    CS89x0 support' CONFIG_CS89x0
-      fi
+      tristate '    CS89x0 support' CONFIG_CS89x0
       tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
       tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
       tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
@@ -207,27 +206,6 @@
 	 bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
       fi
    fi
-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
-      bool '  Dayna firmware support' CONFIG_COPS_DAYNA
-      bool '  Tangent firmware support' CONFIG_COPS_TANGENT
-   fi
-   dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
-   if [ "$CONFIG_IPDDP" != "n" ]; then
-      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
diff -u --recursive --new-file v2.3.49/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.49/linux/drivers/net/Makefile	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/Makefile	Mon Mar  6 15:31:17 2000
@@ -18,7 +18,7 @@
 MOD_SUB_DIRS :=
 MOD_IN_SUB_DIRS :=
 ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \
-		arcnet skfp tulip
+		arcnet skfp tulip appletalk
 
 O_TARGET := net.o
 MOD_LIST_NAME := NET_MODULES
@@ -104,6 +104,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_ATALK),y)
+SUB_DIRS += appletalk
+MOD_IN_SUB_DIRS += appletalk
+else
+  ifeq ($(CONFIG_ATALK),m)
+  MOD_IN_SUB_DIRS += appletalk
+  endif
+endif
+
 #
 # link order important here
 #
@@ -163,8 +172,10 @@
 #
 
 obj-$(CONFIG_AIRONET4500) 	+= aironet4500_core.o
+obj-$(CONFIG_AIRONET4500_CS) 	+= aironet4500_core.o
 obj-$(CONFIG_AIRONET4500_NONCS)  += aironet4500_card.o
 obj-$(CONFIG_AIRONET4500_PROC)	+= aironet4500_proc.o
+obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_proc.o
 
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
@@ -280,9 +291,6 @@
 obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_CS89x0) += cs89x0.o
-obj-$(CONFIG_LTPC) += ltpc.o
-obj-$(CONFIG_COPS) += cops.o
-obj-$(CONFIG_IPDDP) += ipddp.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
diff -u --recursive --new-file v2.3.49/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.3.49/linux/drivers/net/acenic.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/acenic.c	Fri Mar  3 21:34:35 2000
@@ -83,13 +83,13 @@
  * They used the DEC vendor ID by mistake
  */
 #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
-#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a
+#define PCI_DEVICE_ID_FARALLON_PN9000SX	0x1a
 #endif
 #ifndef PCI_VENDOR_ID_SGI
-#define PCI_VENDOR_ID_SGI             0x10a9
+#define PCI_VENDOR_ID_SGI		0x10a9
 #endif
 #ifndef PCI_DEVICE_ID_SGI_ACENIC
-#define PCI_DEVICE_ID_SGI_ACENIC      0x0009
+#define PCI_DEVICE_ID_SGI_ACENIC	0x0009
 #endif
 
 #ifndef wmb
@@ -100,6 +100,11 @@
 #define __exit
 #endif
 
+#ifndef SMP_CACHE_BYTES
+#define SMP_CACHE_BYTES	L1_CACHE_BYTES
+#endif
+
+
 #if (LINUX_VERSION_CODE < 0x02030e)
 #define net_device device
 #endif
@@ -121,7 +126,7 @@
 	return virt_ptr;
 }
 #define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
-#define pci_map_single(cookie, address, size, dir)		virt_to_bus(address)
+#define pci_map_single(cookie, address, size, dir)	virt_to_bus(address)
 #define pci_unmap_single(cookie, address, size, dir)
 #endif
 
@@ -140,18 +145,22 @@
 	dev->start = 1;
 }
 
-#define ace_mark_net_bh(foo)				mark_bh(foo)
-#define ace_if_busy(dev)	dev->tbusy
-#define ace_if_running(dev)	dev->start
-#define ace_if_down(dev)	{do{dev->start = 0;}while (0);}
+#define ace_mark_net_bh(foo)		mark_bh(foo)
+#define netif_queue_stopped(dev)	dev->tbusy
+#define netif_running(dev)		dev->start
+#define ace_if_down(dev)		{do{dev->start = 0;}while (0);}
 #else
 #define NET_BH			0
 #define ace_mark_net_bh(foo)	{do{} while(0);}
-#define ace_if_busy(dev)	netif_queue_stopped(dev)
-#define ace_if_running(dev)	netif_running(dev)
 #define ace_if_down(dev)	{do{} while(0);}
 #endif
 
+
+#define ACE_MAX_MOD_PARMS	8
+#define BOARD_IDX_STATIC	0
+#define BOARD_IDX_OVERFLOW	-1
+
+
 #include "acenic.h"
 
 /*
@@ -336,30 +345,41 @@
 #define ACE_STD_BUFSIZE		(ACE_STD_MTU + ETH_HLEN + 2+4+16)
 #define ACE_JUMBO_BUFSIZE	(ACE_JUMBO_MTU + ETH_HLEN + 2+4+16)
 
-#define DEF_TX_RATIO		24
 /*
  * There seems to be a magic difference in the effect between 995 and 996
  * but little difference between 900 and 995 ... no idea why.
+ *
+ * There is now a default set of tuning parameters which is set, depending
+ * on whether or not the user enables Jumbo frames. It's assumed that if
+ * Jumbo frames are enabled, the user wants optimal tuning for that case.
  */
-#define DEF_TX_COAL		996
+#define DEF_TX_COAL		400 /* 996 */
 #define DEF_TX_MAX_DESC		40
-#define DEF_RX_COAL		1000
+#define DEF_RX_COAL		120 /* 1000 */
 #define DEF_RX_MAX_DESC		25
+#define DEF_TX_RATIO		21 /* 24 */
+
+#define DEF_JUMBO_TX_COAL	20
+#define DEF_JUMBO_TX_MAX_DESC	60
+#define DEF_JUMBO_RX_COAL	30
+#define DEF_JUMBO_RX_MAX_DESC	6
+#define DEF_JUMBO_TX_RATIO	21
+
 #define TX_COAL_INTS_ONLY	0	/* seems not worth it */
 #define DEF_TRACE		0
-#define DEF_STAT		2 * TICKS_PER_SEC
+#define DEF_STAT		(2 * TICKS_PER_SEC)
 
-static int link[8] = {0, };
-static int trace[8] = {0, };
-static int tx_coal_tick[8] = {0, };
-static int rx_coal_tick[8] = {0, };
-static int max_tx_desc[8] = {0, };
-static int max_rx_desc[8] = {0, };
-static int tx_ratio[8] = {0, };
-static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1};
+static int link[ACE_MAX_MOD_PARMS] = {0, };
+static int trace[ACE_MAX_MOD_PARMS] = {0, };
+static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
+static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
+static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, };
+static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, };
+static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, };
+static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static const char __initdata *version = 
-  "acenic.c: v0.41 02/16/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
+  "acenic.c: v0.42 03/02/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev = NULL;
@@ -469,11 +489,6 @@
 
 		pci_set_master(pdev);
 
-#ifdef __sparc__
-		/* NOTE: Cache line size is in 32-bit word units. */
-		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
 		/*
 		 * Remap the regs into kernel space - this is abuse of
 		 * dev->base_addr since it was means for I/O port
@@ -484,7 +499,6 @@
 #else
 		dev->base_addr = pdev->resource[0].start;
 #endif
-
 		ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
 		if (!ap->regs) {
 			printk(KERN_ERR "%s:  Unable to map I/O register, "
@@ -540,8 +554,7 @@
 		if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
 			printk(KERN_ERR "%s: Driver compiled without Tigon I"
 			       " support - NIC disabled\n", dev->name);
-			iounmap(ap->regs);
-			unregister_netdev(dev);
+			ace_init_cleanup(dev);
 			continue;
 		}
 #endif
@@ -550,13 +563,17 @@
 			continue;
 
 #ifdef MODULE
-		if (ace_init(dev, boards_found))
-			continue;
+		if (boards_found >= ACE_MAX_MOD_PARMS)
+			ap->board_idx = BOARD_IDX_OVERFLOW;
+		else
+			ap->board_idx = boards_found;
 #else
-		if (ace_init(dev, -1))
-			continue;
+		ap->board_idx = BOARD_IDX_STATIC;
 #endif
 
+		if (ace_init(dev))
+			continue;
+
 		boards_found++;
 	}
 
@@ -566,20 +583,16 @@
 	 * or more boards. Otherwise, return failure (-ENODEV).
 	 */
 
-#ifdef MODULE
-	return boards_found;
-#else
 	if (boards_found > 0)
 		return 0;
 	else
 		return -ENODEV;
-#endif
 }
 
 
 #ifdef MODULE
 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
-MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver");
+MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
@@ -597,7 +610,7 @@
 
 	while (root_dev) {
 		next = ((struct ace_private *)root_dev->priv)->next;
-		ap = (struct ace_private *)root_dev->priv;
+		ap = root_dev->priv;
 
 		regs = ap->regs;
 
@@ -670,38 +683,26 @@
 			}
 		}
 
-		ace_free_descriptors(root_dev);
-
-		if (ap->trace_buf)
-			kfree(ap->trace_buf);
-		if (ap->info)
-			pci_free_consistent(ap->pdev, sizeof(struct ace_info),
-					    ap->info, ap->info_dma);
-		if (ap->skb)
-			kfree(ap->skb);
-		if (root_dev->irq)
-			free_irq(root_dev->irq, root_dev);
-		unregister_netdev(root_dev);
-		iounmap(regs);
+		ace_init_cleanup(root_dev);
 		kfree(root_dev);
-
 		root_dev = next;
 	}
 }
+#endif
 
 
 int __init ace_module_init(void)
 {
-	int cards;
+	int status;
 
 	root_dev = NULL;
 
 #ifdef NEW_NETINIT
-	cards = acenic_probe();
+	status = acenic_probe();
 #else
-	cards = acenic_probe(NULL);
+	status = acenic_probe(NULL);
 #endif
-	return cards ? 0 : -ENODEV;
+	return status;
 }
 
 
@@ -717,7 +718,6 @@
 	ace_module_cleanup();
 }
 #endif
-#endif
 
 
 #if (LINUX_VERSION_CODE >= 0x02032a)
@@ -817,10 +817,36 @@
 
 fail:
 	/* Clean up. */
+	ace_init_cleanup(dev);
+	return 1;
+}
+
+
+/*
+ * Generic cleanup handling data allocated during init. Used when the
+ * module is unloaded or if an error occurs during initialization
+ */
+static void ace_init_cleanup(struct net_device *dev)
+{
+	struct ace_private *ap;
+
+	ap = dev->priv;
+
 	ace_free_descriptors(dev);
-	iounmap(ap->regs);
+
+	if (ap->info)
+		pci_free_consistent(ap->pdev, sizeof(struct ace_info),
+				    ap->info, ap->info_dma);
+	if (ap->skb)
+		kfree(ap->skb);
+	if (ap->trace_buf)
+		kfree(ap->trace_buf);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+
 	unregister_netdev(dev);
-	return 1;
+	iounmap(ap->regs);
 }
 
 
@@ -840,19 +866,22 @@
 }
 
 
-static int __init ace_init(struct net_device *dev, int board_idx)
+static int __init ace_init(struct net_device *dev)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
 	struct ace_info *info = NULL;
 	unsigned long tmp_ptr, myjif;
 	u32 tig_ver, mac1, mac2, tmp, pci_state;
-	int ecode = 0;
+	int board_idx, ecode = 0;
 	short i;
+	unsigned char cache;
 
 	ap = dev->priv;
 	regs = ap->regs;
 
+	board_idx = ap->board_idx;
+
 	/*
 	 * aman@sgi.com - its useful to do a NIC reset here to
 	 * address the `Firmware not running' problem subsequent
@@ -968,6 +997,21 @@
 	dev->dev_addr[4] = (mac2 >> 8) & 0xff;
 	dev->dev_addr[5] = mac2 & 0xff;
 
+	/*
+	 * Looks like this is necessary to deal with on all architectures,
+	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
+	 * Ie. having two NICs in the machine, one will have the cache
+	 * line set at boot time, the other will not.
+	 */
+	pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache);
+	if ((cache << 2) != SMP_CACHE_BYTES) {
+		printk(KERN_INFO "  PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, correcting to %i\n",
+		       (cache << 2), SMP_CACHE_BYTES);
+		pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE,
+				      SMP_CACHE_BYTES >> 2);
+	}
+
 	pci_state = readl(&regs->PciState);
 	printk(KERN_INFO "  PCI bus width: %i bits, speed: %iMHz, "
 	       "latency: %i clks\n",
@@ -991,19 +1035,20 @@
 		/*
 		 * Tuning parameters only supported for 8 cards
 		 */
-		if (board_idx > 7 || dis_pci_mem_inval[board_idx]) {
+		if (board_idx == BOARD_IDX_OVERFLOW ||
+		    dis_pci_mem_inval[board_idx]) {
 			if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
 				ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
 				pci_write_config_word(ap->pdev, PCI_COMMAND,
 						      ap->pci_command);
-				printk(KERN_INFO "%s: disabling PCI memory "
-				       "write and invalidate\n", dev->name);
+				printk(KERN_INFO "  Disabling PCI memory "
+				       "write and invalidate\n");
 			}
 		} else if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
-			printk(KERN_INFO "%s: PCI memory write & invalidate "
-			       "enabled by BIOS, enabling counter "
-			       "measures\n", dev->name);
-			switch(L1_CACHE_BYTES) {
+			printk(KERN_INFO "  PCI memory write & invalidate "
+			       "enabled by BIOS, enabling counter measures\n");
+			
+			switch(SMP_CACHE_BYTES) {
 			case 16:
 				tmp |= DMA_WRITE_MAX_16;
 				break;
@@ -1023,8 +1068,10 @@
 			}
 		}
 	}
+
 #ifdef __sparc__
-	/* On this platform, we know what the best dma settings
+	/*
+	 * On this platform, we know what the best dma settings
 	 * are.  We use 64-byte maximum bursts, because if we
 	 * burst larger than the cache line size (or even cross
 	 * a 64byte boundry in a single burst) the UltraSparc
@@ -1034,12 +1081,18 @@
 	 * set will give the PCI controller proper hints about
 	 * prefetching.
 	 */
-	tmp = (tmp & ~(0xfc));
+	tmp = tmp & ~DMA_READ_WRITE_MASK;
 	tmp |= DMA_READ_MAX_64;
 	tmp |= DMA_WRITE_MAX_64;
 #endif
 	writel(tmp, &regs->PciState);
 
+	if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) {
+		printk(KERN_INFO "  Enabling PCI Fast Back to Back\n");
+		ap->pci_command |= PCI_COMMAND_FAST_BACK;
+		pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command);
+	}
+		
 	/*
 	 * Initialize the generic info block and the command+event rings
 	 * and the control blocks for the transmit and receive rings
@@ -1213,21 +1266,15 @@
 	writel(1, &regs->AssistState);
 
 	writel(DEF_STAT, &regs->TuneStatTicks);
-
-	writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
-	writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
-	writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
-	writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
 	writel(DEF_TRACE, &regs->TuneTrace);
-	writel(DEF_TX_RATIO, &regs->TxBufRat);
 
-	if (board_idx >= 8) {
-		printk(KERN_WARNING "%s: more then 8 NICs detected, "
-		       "ignoring module parameters!\n", dev->name);
-		board_idx = -1;
-	}
+	ace_set_rxtx_parms(dev, 0);
 
-	if (board_idx >= 0) {
+	if (board_idx == BOARD_IDX_OVERFLOW) {
+		printk(KERN_WARNING "%s: more then %i NICs detected, "
+		       "ignoring module parameters!\n",
+		       dev->name, ACE_MAX_MOD_PARMS);
+	} else if (board_idx >= 0) {
 		if (tx_coal_tick[board_idx])
 			writel(tx_coal_tick[board_idx],
 			       &regs->TuneTxCoalTicks);
@@ -1352,8 +1399,6 @@
 			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
 			       &regs->CpuBCtrl);
 		writel(0, &regs->Mb0Lo);
-		free_irq(dev->irq, dev);
-		dev->irq = 0;
 
 		ecode = -EBUSY;
 		goto init_error;
@@ -1376,27 +1421,63 @@
 			       "the RX mini ring\n", dev->name);
 	}
 	return 0;
+
  init_error:
-	iounmap(ap->regs);
-	unregister_netdev(dev);
-	if (ap->skb) {
-		kfree(ap->skb);
-		ap->skb = NULL;
-	}
-	if (ap->info)
-		pci_free_consistent(ap->pdev, sizeof(struct ace_info),
-				    info, ap->info_dma);
+	ace_init_cleanup(dev);
 	return ecode;
 }
 
 
+static void ace_set_rxtx_parms(struct net_device *dev, int jumbo)
+{
+	struct ace_private *ap;
+	struct ace_regs *regs;
+	int board_idx;
+
+	ap = dev->priv;
+	regs = ap->regs;
+
+	board_idx = ap->board_idx;
+
+	if (board_idx >= 0) {
+		if (!jumbo) {
+			if (!tx_coal_tick[board_idx])
+				writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
+			if (!max_tx_desc[board_idx])
+				writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
+			if (!rx_coal_tick[board_idx])
+				writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
+			if (!max_rx_desc[board_idx])
+				writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
+			if (!tx_ratio[board_idx])
+				writel(DEF_TX_RATIO, &regs->TxBufRat);
+		} else {
+			if (!tx_coal_tick[board_idx])
+				writel(DEF_JUMBO_TX_COAL,
+				       &regs->TuneTxCoalTicks);
+			if (!max_tx_desc[board_idx])
+				writel(DEF_JUMBO_TX_MAX_DESC,
+				       &regs->TuneMaxTxDesc);
+			if (!rx_coal_tick[board_idx])
+				writel(DEF_JUMBO_RX_COAL,
+				       &regs->TuneRxCoalTicks);
+			if (!max_rx_desc[board_idx])
+				writel(DEF_JUMBO_RX_MAX_DESC,
+				       &regs->TuneMaxRxDesc);
+			if (!tx_ratio[board_idx])
+				writel(DEF_JUMBO_TX_RATIO, &regs->TxBufRat);
+		}
+	}
+}
+
+
 /*
  * Monitor the card to detect hangs.
  */
 static void ace_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct ace_private *ap = (struct ace_private *)dev->priv;
+	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 
 	/*
@@ -1459,7 +1540,7 @@
 {
 #if 0
 	if (!ap->trace_buf)
-		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)));
+		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)))
 		    return;
 #endif
 }
@@ -1664,7 +1745,7 @@
 {
 	struct ace_private *ap;
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 
 	while (evtcsm != evtprd) {
 		switch (ap->evt_ring[evtcsm].evt) {
@@ -1742,7 +1823,7 @@
 
 static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 {
-	struct ace_private *ap = (struct ace_private *)dev->priv;
+	struct ace_private *ap = dev->priv;
 	u32 idx;
 	int mini_count = 0, std_count = 0;
 
@@ -1795,7 +1876,8 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-		pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE);
+		pci_unmap_single(ap->pdev, rip->mapping, mapsize,
+				 PCI_DMA_FROMDEVICE);
 		skb_put(skb, retdesc->size);
 #if 0
 		/* unncessary */
@@ -1860,7 +1942,7 @@
 	u32 txcsm, rxretcsm, rxretprd;
 	u32 evtcsm, evtprd;
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 	regs = ap->regs;
 
 	/*
@@ -1902,7 +1984,8 @@
 
 			ap->stats.tx_packets++;
 			ap->stats.tx_bytes += skb->len;
-			pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
+			pci_unmap_single(ap->pdev, mapping, skb->len,
+					 PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(skb);
 
 			ap->skb->tx_skbuff[idx].skb = NULL;
@@ -1928,7 +2011,7 @@
 		 * Ie. skip the comparison of the tx producer vs. the
 		 * consumer.
 		 */
-		if (ace_if_busy(dev) && xchg(&ap->tx_full, 0)) {
+		if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) {
 			/*
 			 * This does not need to be atomic (and expensive),
 			 * I've seen cases where it would fail otherwise ;-(
@@ -1959,7 +2042,7 @@
 	 * This has to go last in the interrupt handler and run with
 	 * the spin lock released ... what lock?
 	 */
-	if (ace_if_running(dev)) {
+	if (netif_running(dev)) {
 		int cur_size;
 		int run_bh = 0;
 
@@ -2108,7 +2191,7 @@
 	ace_if_down(dev);
 	netif_stop_queue(dev);
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 	regs = ap->regs;
 
 	del_timer(&ap->timer);
@@ -2143,7 +2226,8 @@
 			writel(0, &ap->tx_ring[i].addr.addrhi);
 			writel(0, &ap->tx_ring[i].addr.addrlo);
 			writel(0, &ap->tx_ring[i].flagsize);
-			pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
+			pci_unmap_single(ap->pdev, mapping, skb->len,
+					 PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
 			ap->skb->tx_skbuff[i].skb = NULL;
 		}
@@ -2165,7 +2249,7 @@
 
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct ace_private *ap = (struct ace_private *)dev->priv;
+	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 	unsigned long addr;
 	u32 idx, flagsize;
@@ -2193,7 +2277,8 @@
 
 	ap->skb->tx_skbuff[idx].skb = skb;
 	ap->skb->tx_skbuff[idx].mapping =
-		pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+		pci_map_single(ap->pdev, skb->data, skb->len,
+			       PCI_DMA_TODEVICE);
 	addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
 #if (BITS_PER_LONG == 64)
 	writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
@@ -2264,12 +2349,13 @@
 			ap->jumbo = 1;
 			if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
 				ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
-			ap->jumbo = 1;
+			ace_set_rxtx_parms(dev, 1);
 		}
 	} else {
 		netif_stop_queue(dev);
 		while (test_and_set_bit(0, &ap->jumbo_refill_busy));
 		synchronize_irq();
+		ace_set_rxtx_parms(dev, 0);
 		if (ap->jumbo){
 			struct cmd cmd;
 
@@ -2287,7 +2373,7 @@
 static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 #ifdef ETHTOOL
-	struct ace_private *ap = (struct ace_private *) dev->priv;
+	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 	struct ethtool_cmd ecmd;
 	u32 link, speed;
@@ -2429,7 +2515,7 @@
 	u16 *da;
 	struct cmd cmd;
 
-	if(ace_if_running(dev))
+	if(netif_running(dev))
 		return -EBUSY;
 
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
@@ -2587,7 +2673,7 @@
 	struct ace_private *ap;
 	struct ace_regs *regs;
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 	regs = ap->regs;
 
 	if (!(readl(&regs->CpuCtrl) & CPU_HALTED)) {
diff -u --recursive --new-file v2.3.49/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.3.49/linux/drivers/net/acenic.h	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/acenic.h	Fri Mar  3 21:34:35 2000
@@ -233,6 +233,7 @@
 #define DMA_WRITE_MAX_128	0xa0
 #define DMA_WRITE_MAX_256	0xc0
 #define DMA_WRITE_MAX_1K	0xe0
+#define DMA_READ_WRITE_MASK	0xfc
 #define MEM_READ_MULTIPLE	0x00020000
 #define PCI_66MHZ		0x00080000
 #define PCI_32BIT		0x00100000
@@ -635,6 +636,7 @@
 	unsigned char		*trace_buf;
 	struct pci_dev		*pdev;
 	struct net_device	*next;
+	int			board_idx;
 	u16			pci_command;
 	u8			pci_latency;
 	char			name[48];
@@ -698,7 +700,7 @@
 /*
  * Prototypes
  */
-static int ace_init(struct net_device *dev, int board_idx);
+static int ace_init(struct net_device *dev);
 static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
 static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
 static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
@@ -717,8 +719,10 @@
 #endif
 static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static int ace_set_mac_addr(struct net_device *dev, void *p);
+static void ace_set_rxtx_parms(struct net_device *dev, int jumbo);
 static int ace_allocate_descriptors(struct net_device *dev);
 static void ace_free_descriptors(struct net_device *dev);
+static void ace_init_cleanup(struct net_device *dev);
 static struct net_device_stats *ace_get_stats(struct net_device *dev);
 static int read_eeprom_byte(struct net_device *dev, unsigned long offset);
 
diff -u --recursive --new-file v2.3.49/linux/drivers/net/aironet4500_core.c linux/drivers/net/aironet4500_core.c
--- v2.3.49/linux/drivers/net/aironet4500_core.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/aironet4500_core.c	Mon Mar  6 15:44:54 2000
@@ -18,6 +18,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
@@ -2521,7 +2522,7 @@
 
 struct net_device * aironet4500_devices[MAX_AWCS]  = {NULL,NULL,NULL,NULL};
 
-static int awc_debug = 0; //  0xffffff;
+int awc_debug = 0; //  0xffffff;
 static int p802_11_send  =  0; // 1
 
 static int awc_process_tx_results = 0;
@@ -3197,9 +3198,7 @@
 	return 0;
 };
 
-#ifdef MODULE
-        
-int init_module(void)
+static int aironet_core_init(void)
 {
 //	unsigned long flags;
 
@@ -3210,11 +3209,12 @@
 
 }
 
-void cleanup_module(void)
+static void aironet_core_exit(void)
 {
 	printk(KERN_INFO "aironet4500 unloading core module \n");
 
 }
-
-#endif
         
+module_init(aironet_core_init);
+module_exit(aironet_core_exit);
+
diff -u --recursive --new-file v2.3.49/linux/drivers/net/aironet4500_proc.c linux/drivers/net/aironet4500_proc.c
--- v2.3.49/linux/drivers/net/aironet4500_proc.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/aironet4500_proc.c	Mon Mar  6 15:45:09 2000
@@ -10,6 +10,7 @@
  *
  */
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 
@@ -520,7 +521,7 @@
    return 0;
 };
 
-int init_module(void) {
+static int aironet_proc_init(void) {
 	int i=0;
 
 	AWC_ENTRY_EXIT_DEBUG("init_module");
@@ -539,7 +540,7 @@
 
 };
 
-void cleanup_module(void){
+static void aironet_proc_exit(void){
 
 	int i=0;
 	AWC_ENTRY_EXIT_DEBUG("cleanup_module");
@@ -552,4 +553,7 @@
 	AWC_ENTRY_EXIT_DEBUG("exit");
 };
 
-#endif // whole proc system styff
\ No newline at end of file
+module_init(aironet_proc_init);
+module_exit(aironet_proc_exit);
+
+#endif // whole proc system styff
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/Config.in linux/drivers/net/appletalk/Config.in
--- v2.3.49/linux/drivers/net/appletalk/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/Config.in	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,20 @@
+#
+# Appletalk driver configuration
+#
+
+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
+     bool '  Dayna firmware support' CONFIG_COPS_DAYNA
+     bool '  Tangent firmware support' CONFIG_COPS_TANGENT
+  fi
+  dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
+  if [ "$CONFIG_IPDDP" != "n" ]; then
+     bool '  IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+     bool '  Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
+  fi
+  endmenu
+fi
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/Makefile linux/drivers/net/appletalk/Makefile
--- v2.3.49/linux/drivers/net/appletalk/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/Makefile	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,30 @@
+#
+# Makefile for drivers/net/appletalk
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+obj-y   :=
+obj-n   :=
+obj-m   :=
+obj-    :=
+export-objs :=
+
+obj-$(CONFIG_LTPC) += ltpc.o
+obj-$(CONFIG_COPS) += cops.o
+obj-$(CONFIG_IPDDP) += ipddp.o
+
+L_TARGET := appletalk.a
+L_OBJS   := $(filter-out $(export-objs), $(obj-y))
+LX_OBJS  := $(filter     $(export-objs), $(obj-y))
+M_OBJS   := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS  := $(sort $(filter     $(export-objs), $(obj-m)))
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c
--- v2.3.49/linux/drivers/net/appletalk/cops.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/cops.c	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,1066 @@
+/*      cops.c: LocalTalk driver for Linux.
+ *
+ *	Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ *
+ *	With more than a little help from;
+ *	- Alan Cox <Alan.Cox@linux.org> 
+ *
+ *      Derived from:
+ *      - skeleton.c: A network driver outline for linux.
+ *        Written 1993-94 by Donald Becker.
+ *	- ltpc.c: A driver for the LocalTalk PC card.
+ *	  Written by Bradford W. Johnson.
+ *
+ *      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.
+ *
+ *	Changes:
+ *	19970608	Alan Cox	Allowed dual card type support
+ *					Can set board type in insmod
+ *					Hooks for cops_setup routine
+ *					(not yet implemented).
+ *	19971101	Jay Schulist	Fixes for multiple lt* devices.
+ *	19980607	Steven Hirsch	Fixed the badly broken support
+ *					for Tangent type cards. Only
+ *                                      tested on Daystar LT200. Some
+ *                                      cleanup of formatting and program
+ *                                      logic.  Added emacs 'local-vars'
+ *                                      setup for Jay's brace style.
+ *	20000211	Alan Cox	Cleaned up for softnet
+ */
+
+static const char *version =
+"cops.c:v0.04 6/7/98 Jay Schulist <jschlst@turbolinux.com>\n";
+/*
+ *  Sources:
+ *      COPS Localtalk SDK. This provides almost all of the information
+ *      needed.
+ */
+
+/*
+ * insmod/modprobe configurable stuff.
+ *	- IO Port, choose one your card supports or 0 if you dare.
+ *	- IRQ, also choose one your card supports or nothing and let
+ *	  the driver figure it out.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>	/* For ltalk_setup() */
+#include <linux/delay.h>	/* For udelay() */
+#include <linux/atalk.h>
+
+#include "cops.h"		/* Our Stuff */
+#include "cops_ltdrv.h"		/* Firmware code for Tangent type cards. */
+#include "cops_ffdrv.h"		/* Firmware code for Dayna type cards. */
+
+/*
+ *      The name of the card. Is used for messages and in the requests for
+ *      io regions, irqs and dma channels
+ */
+
+static const char *cardname = "cops";
+
+#ifdef CONFIG_COPS_DAYNA
+static int board_type = DAYNA;	/* Module exported */
+#else
+static int board_type = TANGENT;
+#endif
+
+#ifdef MODULE
+static int io = 0x240;		/* Default IO for Dayna */
+static int irq = 5;		/* Default IRQ */
+#else
+static int io = 0;		/* Default IO for Dayna */
+static int irq = 0;		/* Default IRQ */
+#endif
+
+/*
+ *	COPS Autoprobe information.
+ *	Right now if port address is right but IRQ is not 5 this will
+ *      return a 5 no matter what since we will still get a status response.
+ *      Need one more additional check to narrow down after we have gotten
+ *      the ioaddr. But since only other possible IRQs is 3 and 4 so no real
+ *	hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with
+ *	this driver.
+ * 
+ *	This driver has 2 modes and they are: Dayna mode and Tangent mode.
+ *	Each mode corresponds with the type of card. It has been found
+ *	that there are 2 main types of cards and all other cards are
+ *	the same and just have different names or only have minor differences
+ *	such as more IO ports. As this driver is tested it will
+ *	become more clear on exactly what cards are supported. The driver
+ *	defaults to using Dayna mode. To change the drivers mode, simply
+ *	select Dayna or Tangent mode when configuring the kernel.
+ *
+ *      This driver should support:
+ *      TANGENT driver mode:
+ *              Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
+ *		COPS LT-1
+ *      DAYNA driver mode:
+ *              Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 
+ *		Farallon PhoneNET PC III, Farallon PhoneNET PC II
+ *	Other cards possibly supported mode unkown though:
+ *		Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
+ *
+ *	Cards NOT supported by this driver but supported by the ltpc.c
+ *	driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *		Farallon PhoneNET PC
+ *		Original Apple LocalTalk PC card
+ * 
+ *      N.B.
+ *
+ *      The Daystar Digital LT200 boards do not support interrupt-driven
+ *      IO.  You must specify 'irq=0xff' as a module parameter to invoke
+ *      polled mode.  I also believe that the port probing logic is quite
+ *      dangerous at best and certainly hopeless for a polled card.  Best to 
+ *      specify both. - Steve H.
+ *
+ */
+
+/*
+ * Zero terminated list of IO ports to probe.
+ */
+
+static unsigned int cops_portlist[] = { 
+	0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 
+	0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360,
+	0
+};
+
+/*
+ * Zero terminated list of IRQ ports to probe.
+ */
+
+static int cops_irqlist[] = {
+	5, 4, 3, 0 
+};
+
+static struct timer_list cops_timer;
+
+/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
+#ifndef COPS_DEBUG
+#define COPS_DEBUG 1 
+#endif
+static unsigned int cops_debug = COPS_DEBUG;
+
+/* The number of low I/O ports used by the card. */
+#define COPS_IO_EXTENT       8
+
+/* Information that needs to be kept for each board. */
+
+struct cops_local
+{
+        struct net_device_stats stats;
+        int board;			/* Holds what board type is. */
+	int nodeid;			/* Set to 1 once have nodeid. */
+        unsigned char node_acquire;	/* Node ID when acquired. */
+        struct at_addr node_addr;	/* Full node addres */
+};
+
+/* Index to functions, as function prototypes. */
+extern int  cops_probe (struct net_device *dev);
+static int  cops_probe1 (struct net_device *dev, int ioaddr);
+static int  cops_irq (int ioaddr, int board);
+
+static int  cops_open (struct net_device *dev);
+static int  cops_jumpstart (struct net_device *dev);
+static void cops_reset (struct net_device *dev, int sleep);
+static void cops_load (struct net_device *dev);
+static int  cops_nodeid (struct net_device *dev, int nodeid);
+
+static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void cops_poll (unsigned long ltdev);
+static void cops_timeout(struct net_device *dev);
+static void cops_rx (struct net_device *dev);
+static int  cops_send_packet (struct sk_buff *skb, struct net_device *dev);
+static void set_multicast_list (struct net_device *dev);
+static int  cops_hard_header (struct sk_buff *skb, struct net_device *dev,
+			      unsigned short type, void *daddr, void *saddr, 
+			      unsigned len);
+
+static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int  cops_close (struct net_device *dev);
+static struct net_device_stats *cops_get_stats (struct net_device *dev);
+
+
+/*
+ *      Check for a network adaptor of this type, and return '0' iff one exists.
+ *      If dev->base_addr == 0, probe all likely locations.
+ *      If dev->base_addr in [1..0x1ff], always return failure.
+ *        otherwise go with what we pass in.
+ */
+int __init cops_probe(struct net_device *dev)
+{
+	int i;
+        int base_addr = dev ? dev->base_addr : 0;
+        
+        if(base_addr == 0 && io)
+        	base_addr=io;
+
+        if(base_addr > 0x1ff)    /* Check a single specified location. */
+                return cops_probe1(dev, base_addr);
+	else if(base_addr != 0)  /* Don't probe at all. */
+               	return -ENXIO;
+	
+	/* FIXME  Does this really work for cards which generate irq?
+	 * It's definitely N.G. for polled Tangent. sh
+	 * Dayna cards don't autoprobe well at all, but if your card is
+	 * at IRQ 5 & IO 0x240 we find it every time. ;) JS
+	 */
+        for(i=0; cops_portlist[i]; i++) {
+		int ioaddr = cops_portlist[i];
+		if(check_region(ioaddr, COPS_IO_EXTENT))
+                        continue;
+                if(cops_probe1(dev, ioaddr) == 0)
+                        return 0;
+        }
+	
+        return -ENODEV;
+}
+
+/*
+ *      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.
+ */
+static int __init cops_probe1(struct net_device *dev, int ioaddr)
+{
+        struct cops_local *lp;
+	static unsigned version_printed = 0;
+
+	int board = board_type;
+	
+        if(cops_debug && version_printed++ == 0)
+		printk("%s", version);
+
+        /*
+         * Since this board has jumpered interrupts, allocate the interrupt
+         * vector now. There is no point in waiting since no other device
+         * can use the interrupt, and this marks the irq as busy. Jumpered
+         * interrupts are typically not reported by the boards, and we must
+         * used AutoIRQ to find them.
+	 */
+	switch (dev->irq)
+	{
+		case 0:
+			/* COPS AutoIRQ routine */
+			dev->irq = cops_irq(ioaddr, board);
+			if(!dev->irq)
+				return -EINVAL;	/* No IRQ found on this port */
+			break;
+
+		case 1:
+			return -EINVAL;
+			break;
+
+		/* Fixup for users that don't know that IRQ 2 is really
+		 * IRQ 9, or don't know which one to set.
+		 */
+		case 2:
+			dev->irq = 9;
+			break;
+
+		/* Polled operation requested. Although irq of zero passed as
+		 * a parameter tells the init routines to probe, we'll
+		 * overload it to denote polled operation at runtime.
+		 */
+		case 0xff:
+			dev->irq = 0;
+			break;
+
+		default:
+			break;
+	}
+
+	/* Reserve any actual interrupt. */
+	if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev))
+		return -EINVAL;
+
+	/* Grab the region so no one else tries to probe our ioports. */
+	request_region(ioaddr, COPS_IO_EXTENT, cardname);
+	dev->base_addr          = ioaddr;
+
+	/* Initialize the private device structure. */
+        dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL);
+        if(dev->priv == NULL)
+        	return -ENOMEM;
+
+        lp = (struct cops_local *)dev->priv;
+        memset(lp, 0, sizeof(struct cops_local));
+
+	/* Copy local board variable to lp struct. */
+	lp->board               = board;
+
+	/* Fill in the fields of the device structure with LocalTalk values. */
+	ltalk_setup(dev);
+
+	dev->hard_start_xmit    = cops_send_packet;
+	dev->tx_timeout		= cops_timeout;
+	dev->watchdog_timeo	= HZ * 2;
+	dev->hard_header	= cops_hard_header;
+        dev->get_stats          = cops_get_stats;
+	dev->open               = cops_open;
+        dev->stop               = cops_close;
+        dev->do_ioctl           = cops_ioctl;
+	dev->set_multicast_list = set_multicast_list;
+        dev->mc_list            = NULL;
+
+	/* Tell the user where the card is and what mode we're in. */
+	if(board==DAYNA)
+		printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
+			dev->name, cardname, ioaddr, dev->irq);
+	if(board==TANGENT) {
+		if(dev->irq)
+			printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
+				dev->name, cardname, ioaddr, dev->irq);
+		else
+			printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
+				dev->name, cardname, ioaddr);
+
+	}
+        return 0;
+}
+
+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.
+         * This really just verifies the IO port but since we only have access
+         * to such a small number of IRQs (5, 4, 3) this is not bad.
+         * This will probably not work for more than one card.
+         */
+        int irqaddr=0;
+        int i, x, status;
+
+        if(board==DAYNA)
+        {
+                outb(0, ioaddr+DAYNA_RESET);
+                inb(ioaddr+DAYNA_RESET);
+                udelay(333333);
+        }
+        if(board==TANGENT)
+        {
+                inb(ioaddr);
+                outb(0, ioaddr);
+                outb(0, ioaddr+TANG_RESET);
+        }
+
+        for(i=0; cops_irqlist[i] !=0; i++)
+        {
+                irqaddr = cops_irqlist[i];
+                for(x = 0xFFFF; x>0; x --)    /* wait for response */
+                {
+                        if(board==DAYNA)
+                        {
+                                status = (inb(ioaddr+DAYNA_CARD_STATUS)&3);
+                                if(status == 1)
+                                        return irqaddr;
+                        }
+                        if(board==TANGENT)
+                        {
+                                if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0)
+                                        return irqaddr;
+                        }
+                }
+        }
+        return 0;       /* no IRQ found */
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ */
+static int cops_open(struct net_device *dev)
+{
+    struct cops_local *lp = (struct cops_local *)dev->priv;
+
+	if(dev->irq==0)
+	{
+		/*
+		 * I don't know if the Dayna-style boards support polled 
+		 * operation.  For now, only allow it for Tangent.
+		 */
+		if(lp->board==TANGENT)	/* Poll 20 times per second */
+		{
+		    init_timer(&cops_timer);
+		    cops_timer.function = cops_poll;
+		    cops_timer.data 	= (unsigned long)dev;
+		    cops_timer.expires 	= jiffies + 5;
+		    add_timer(&cops_timer);
+		} 
+		else 
+		{
+			printk(KERN_WARNING "%s: No irq line set\n", dev->name);
+			return -EAGAIN;
+		}
+	}
+
+	cops_jumpstart(dev);	/* Start the card up. */
+
+	netif_start_queue(dev);
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
+
+        return 0;
+}
+
+/*
+ *	This allows for a dynamic start/restart of the entire card.
+ */
+static int cops_jumpstart(struct net_device *dev)
+{
+	struct cops_local *lp = (struct cops_local *)dev->priv;
+
+	/*
+         *      Once the card has the firmware loaded and has acquired
+         *      the nodeid, if it is reset it will lose it all.
+         */
+        cops_reset(dev,1);	/* Need to reset card before load firmware. */
+        cops_load(dev);		/* Load the firmware. */
+
+	/*
+	 *	If atalkd already gave us a nodeid we will use that
+	 *	one again, else we wait for atalkd to give us a nodeid
+	 *	in cops_ioctl. This may cause a problem if someone steals
+	 *	our nodeid while we are resetting.
+	 */	
+	if(lp->nodeid == 1)
+		cops_nodeid(dev,lp->node_acquire);
+
+	return 0;
+}
+
+static void tangent_wait_reset(int ioaddr)
+{
+	int timeout=0;
+
+	while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+		mdelay(1);   /* Wait 1 second */
+}
+
+/*
+ *      Reset the LocalTalk board.
+ */
+static void cops_reset(struct net_device *dev, int sleep)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr=dev->base_addr;
+
+        if(lp->board==TANGENT)
+        {
+                inb(ioaddr);		/* Clear request latch. */
+                outb(0,ioaddr);		/* Clear the TANG_TX_READY flop. */
+                outb(0, ioaddr+TANG_RESET);	/* Reset the adapter. */
+
+		tangent_wait_reset(ioaddr);
+                outb(0, ioaddr+TANG_CLEAR_INT);
+        }
+        if(lp->board==DAYNA)
+        {
+                outb(0, ioaddr+DAYNA_RESET);	/* Assert the reset port */
+                inb(ioaddr+DAYNA_RESET);	/* Clear the reset */
+                if(sleep)
+                {
+                        long snap=jiffies;
+
+			/* Let card finish initializing, about 1/3 second */
+	                while(jiffies-snap<HZ/3)
+                                schedule();
+                }
+                else
+                        udelay(333333);
+        }
+	netif_wake_queue(dev);
+	return;
+}
+
+static void cops_load (struct net_device *dev)
+{
+        struct ifreq ifr;
+        struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data;
+        struct cops_local *lp=(struct cops_local *)dev->priv;
+        int ioaddr=dev->base_addr;
+	int length, i = 0;
+
+        strcpy(ifr.ifr_name,"lt0");
+
+        /* Get card's firmware code and do some checks on it. */
+#ifdef CONFIG_COPS_DAYNA        
+        if(lp->board==DAYNA)
+        {
+                ltf->length=sizeof(ffdrv_code);
+                ltf->data=ffdrv_code;
+        }
+        else
+#endif        
+#ifdef CONFIG_COPS_TANGENT
+        if(lp->board==TANGENT)
+        {
+                ltf->length=sizeof(ltdrv_code);
+                ltf->data=ltdrv_code;
+        }
+        else
+#endif
+	{
+		printk(KERN_INFO "%s; unsupported board type.\n", dev->name);
+		return;
+	}
+	
+        /* Check to make sure firmware is correct length. */
+        if(lp->board==DAYNA && ltf->length!=5983)
+        {
+                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);
+                return;
+        }
+        if(lp->board==TANGENT && ltf->length!=2501)
+        {
+                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);
+                return;
+        }
+
+        if(lp->board==DAYNA)
+        {
+                /*
+                 *      We must wait for a status response
+                 *      with the DAYNA board.
+                 */
+                while(++i<65536)
+                {
+                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)
+                                break;
+                }
+
+                if(i==65536)
+                        return;
+        }
+
+        /*
+         *      Upload the firmware and kick. Byte-by-byte works nicely here.
+         */
+	i=0;
+        length = ltf->length;
+        while(length--)
+        {
+                outb(ltf->data[i], ioaddr);
+                i++;
+        }
+
+	if(cops_debug > 1)
+		printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
+			dev->name, i, ltf->length);
+
+        if(lp->board==DAYNA) 	/* Tell Dayna to run the firmware code. */
+                outb(1, ioaddr+DAYNA_INT_CARD);
+	else			/* Tell Tang to run the firmware code. */
+		inb(ioaddr);
+
+        if(lp->board==TANGENT)
+        {
+                tangent_wait_reset(ioaddr);
+                inb(ioaddr);	/* Clear initial ready signal. */
+        }
+
+        return;
+}
+
+/*
+ * 	Get the LocalTalk Nodeid from the card. We can suggest
+ *	any nodeid 1-254. The card will try and get that exact
+ *	address else we can specify 0 as the nodeid and the card
+ *	will autoprobe for a nodeid.
+ */
+static int cops_nodeid (struct net_device *dev, int nodeid)
+{
+	struct cops_local *lp = (struct cops_local *) dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if(lp->board == DAYNA)
+        {
+        	/* Empty any pending adapter responses. */
+                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
+                {
+			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupts. */
+        		if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+                		cops_rx(dev);	/* Kick any packets waiting. */
+			schedule();
+                }
+
+                outb(2, ioaddr);       	/* Output command packet length as 2. */
+                outb(0, ioaddr);
+                outb(LAP_INIT, ioaddr);	/* Send LAP_INIT command byte. */
+                outb(nodeid, ioaddr);  	/* Suggest node address. */
+        }
+
+	if(lp->board == TANGENT)
+        {
+                /* Empty any pending adapter responses. */
+                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
+                {
+			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupt. */
+                	cops_rx(dev);          	/* Kick out packets waiting. */
+			schedule();
+                }
+
+		/* Not sure what Tangent does if nodeid picked is used. */
+                if(nodeid == 0)	         		/* Seed. */
+                	nodeid = jiffies&0xFF;		/* Get a random try */
+                outb(2, ioaddr);        		/* Command length LSB */
+                outb(0, ioaddr);       			/* Command length MSB */
+                outb(LAP_INIT, ioaddr); 		/* Send LAP_INIT byte */
+                outb(nodeid, ioaddr); 		  	/* LAP address hint. */
+                outb(0xFF, ioaddr);     		/* Int. level to use */
+        }
+
+	lp->node_acquire=0;		/* Set nodeid holder to 0. */
+        while(lp->node_acquire==0)	/* Get *True* nodeid finally. */
+	{
+		outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear any interrupt. */
+
+		if(lp->board == DAYNA)
+		{
+                	if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+                		cops_rx(dev);	/* Grab the nodeid put in lp->node_acquire. */
+		}
+		if(lp->board == TANGENT)
+		{	
+			if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
+                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
+		}
+		schedule();
+	}
+
+	if(cops_debug > 1)
+		printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
+			dev->name, lp->node_acquire);
+
+	lp->nodeid=1;	/* Set got nodeid to 1. */
+
+        return 0;
+}
+
+/*
+ *	Poll the Tangent type cards to see if we have work.
+ */
+ 
+static void cops_poll(unsigned long ltdev)
+{
+	int ioaddr, status;
+	int boguscount = 0;
+
+	struct net_device *dev = (struct net_device *)ltdev;
+
+	del_timer(&cops_timer);
+
+	if(dev == NULL)
+		return;	/* We've been downed */
+
+	ioaddr = dev->base_addr;
+	do {
+		status=inb(ioaddr+TANG_CARD_STATUS);
+		if(status & TANG_RX_READY)
+			cops_rx(dev);
+		if(status & TANG_TX_READY)
+			netif_wake_queue(dev);
+		status = inb(ioaddr+TANG_CARD_STATUS);
+	} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+
+	cops_timer.expires = jiffies+5;
+	add_timer(&cops_timer);
+
+	return;
+}
+
+/*
+ *      The typical workload of the driver:
+ *      Handle the network interface interrupts.
+ */
+static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+        struct net_device *dev = dev_id;
+        struct cops_local *lp;
+        int ioaddr, status;
+        int boguscount = 0;
+
+        ioaddr = dev->base_addr;
+        lp = (struct cops_local *)dev->priv;
+
+	if(lp->board==DAYNA)
+	{
+		do {
+			outb(0, ioaddr + COPS_CLEAR_INT);
+                       	status=inb(ioaddr+DAYNA_CARD_STATUS);
+                       	if((status&0x03)==DAYNA_RX_REQUEST)
+                       	        cops_rx(dev);
+                	netif_wake_queue(dev);
+		} while(++boguscount < 20);
+	}
+	else
+	{
+		do {
+                       	status=inb(ioaddr+TANG_CARD_STATUS);
+			if(status & TANG_RX_READY)
+				cops_rx(dev);
+			if(status & TANG_TX_READY)
+				netif_wake_queue(dev);
+			status=inb(ioaddr+TANG_CARD_STATUS);
+		} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
+	}
+
+        return;
+}
+
+/*
+ *      We have a good packet(s), get it/them out of the buffers.
+ */
+static void cops_rx(struct net_device *dev)
+{
+        int pkt_len = 0;
+        int rsp_type = 0;
+        struct sk_buff *skb;
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr = dev->base_addr;
+        int boguscount = 0;
+        unsigned long flags;
+
+
+	save_flags(flags);
+        cli();  /* Disable interrupts. */
+
+        if(lp->board==DAYNA)
+        {
+                outb(0, ioaddr);                /* Send out Zero length. */
+                outb(0, ioaddr);
+                outb(DATA_READ, ioaddr);        /* Send read command out. */
+
+                /* Wait for DMA to turn around. */
+                while(++boguscount<1000000)
+                {
+                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
+                                break;
+                }
+
+                if(boguscount==1000000)
+                {
+                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);
+                        return;
+                }
+        }
+
+        /* Get response length. */
+	if(lp->board==DAYNA)
+        	pkt_len = inb(ioaddr) & 0xFF;
+	else
+		pkt_len = inb(ioaddr) & 0x00FF;
+        pkt_len |= (inb(ioaddr) << 8);
+        /* Input IO code. */
+        rsp_type=inb(ioaddr);
+
+        /* Malloc up new buffer. */
+        skb = dev_alloc_skb(pkt_len);
+        if(skb == NULL)
+        {
+                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
+			dev->name);
+                lp->stats.rx_dropped++;
+                while(pkt_len--)        /* Discard packet */
+                        inb(ioaddr);
+                return;
+        }
+        skb->dev = dev;
+        skb_put(skb, pkt_len);
+        skb->protocol = htons(ETH_P_LOCALTALK);
+
+        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
+
+        if(lp->board==DAYNA)
+                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
+
+        restore_flags(flags);  /* Restore interrupts. */
+
+        /* Check for bad response length */
+        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
+        {
+		printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
+			dev->name, pkt_len);
+                lp->stats.tx_errors++;
+                kfree_skb(skb);
+                return;
+        }
+
+        /* Set nodeid and then get out. */
+        if(rsp_type == LAP_INIT_RSP)
+        {	/* Nodeid taken from received packet. */
+                lp->node_acquire = skb->data[0];
+                kfree_skb(skb);
+                return;
+        }
+
+        /* One last check to make sure we have a good packet. */
+        if(rsp_type != LAP_RESPONSE)
+        {
+                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
+                lp->stats.tx_errors++;
+                kfree_skb(skb);
+                return;
+        }
+
+        skb->mac.raw    = skb->data;    /* Point to entire packet. */
+        skb_pull(skb,3);
+        skb->h.raw      = skb->data;    /* Point to data (Skip header). */
+
+        /* Update the counters. */
+        lp->stats.rx_packets++;
+        lp->stats.rx_bytes += skb->len;
+
+        /* Send packet to a higher place. */
+        netif_rx(skb);
+
+        return;
+}
+
+static void cops_timeout(struct net_device *dev)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr = dev->base_addr;
+
+	lp->stats.tx_errors++;
+        if(lp->board==TANGENT)
+        {
+		if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+               		printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
+	}
+	printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
+	cops_jumpstart(dev);	/* Restart the card. */
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+
+/*
+ *	Make the card transmit a LocalTalk packet.
+ */
+
+static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        int ioaddr = dev->base_addr;
+        unsigned long flags;
+
+        /*
+         * Block a timer-based transmit from overlapping. 
+	 */
+	 
+	netif_stop_queue(dev);
+
+	save_flags(flags);	
+	cli();	/* Disable interrupts. */
+	if(lp->board == DAYNA)	 /* Wait for adapter transmit buffer. */
+		while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+	if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
+		while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
+
+	/* Output IO length. */
+	outb(skb->len, ioaddr);
+	if(lp->board == DAYNA)
+               	outb(skb->len >> 8, ioaddr);
+	else
+		outb((skb->len >> 8)&0x0FF, ioaddr);
+
+	/* Output IO code. */
+	outb(LAP_WRITE, ioaddr);
+
+	if(lp->board == DAYNA)	/* Check the transmit buffer again. */
+        	while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+
+	outsb(ioaddr, skb->data, skb->len);	/* Send out the data. */
+
+	if(lp->board==DAYNA)	/* Dayna requires you kick the card */
+		outb(1, ioaddr+DAYNA_INT_CARD);
+
+	restore_flags(flags);	/* Restore interrupts. */
+
+	/* Done sending packet, update counters and cleanup. */
+	lp->stats.tx_packets++;
+	lp->stats.tx_bytes += skb->len;
+	dev->trans_start = jiffies;
+	dev_kfree_skb (skb);
+        return 0;
+}
+
+/*
+ *	Dummy function to keep the Appletalk layer happy.
+ */
+ 
+static void set_multicast_list(struct net_device *dev)
+{
+        if(cops_debug >= 3)
+		printk("%s: set_multicast_list executed\n", dev->name);
+}
+
+/*
+ *      Another Dummy function to keep the Appletalk layer happy.
+ */
+ 
+static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
+			    unsigned short type, void *daddr, void *saddr, 
+			    unsigned len)
+{
+        if(cops_debug >= 3)
+                printk("%s: cops_hard_header executed. Wow!\n", dev->name);
+        return 0;
+}
+
+/*
+ *      System ioctls for the COPS LocalTalk card.
+ */
+ 
+static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr;
+        struct at_addr *aa=(struct at_addr *)&lp->node_addr;
+
+        switch(cmd)
+        {
+                case SIOCSIFADDR:
+			/* Get and set the nodeid and network # atalkd wants. */
+			cops_nodeid(dev, sa->sat_addr.s_node);
+			aa->s_net               = sa->sat_addr.s_net;
+                        aa->s_node              = lp->node_acquire;
+
+			/* Set broardcast address. */
+                        dev->broadcast[0]       = 0xFF;
+			
+			/* Set hardware address. */
+                        dev->dev_addr[0]        = aa->s_node;
+                        dev->addr_len           = 1;
+                        return 0;
+
+                case SIOCGIFADDR:
+                        sa->sat_addr.s_net      = aa->s_net;
+                        sa->sat_addr.s_node     = aa->s_node;
+                        return 0;
+
+                default:
+                        return -EOPNOTSUPP;
+        }
+}
+
+/*
+ *	The inverse routine to cops_open().
+ */
+ 
+static int cops_close(struct net_device *dev)
+{
+	struct cops_local *lp = (struct cops_local *)dev->priv;
+
+	/* If we were running polled, yank the timer.
+	 */
+	if(lp->board==TANGENT && dev->irq==0)
+		del_timer(&cops_timer);
+
+	netif_stop_queue(dev);
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
+	
+        return 0;
+}
+
+/*
+ *      Get the current statistics.
+ *      This may be called with the card open or closed.
+ */
+static struct net_device_stats *cops_get_stats(struct net_device *dev)
+{
+        struct cops_local *lp = (struct cops_local *)dev->priv;
+        return &lp->stats;
+}
+
+#ifdef MODULE
+static char lt_name[16];
+
+static struct net_device cops0_dev =
+{
+	lt_name,	/* device name */
+        0, 0, 0, 0,
+        0x0, 0,  /* I/O address, IRQ */
+        0, 0, 0, NULL, cops_probe
+};
+
+
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(board_type, "i");
+
+int init_module(void)
+{
+        int result, err;
+
+        if(io == 0)
+		printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
+			cardname);
+
+        /* Copy the parameters from insmod into the device structure. */
+        cops0_dev.base_addr = io;
+        cops0_dev.irq       = irq;
+
+	err=dev_alloc_name(&cops0_dev, "lt%d");
+        if(err < 0)
+                return err;
+
+        if((result = register_netdev(&cops0_dev)) != 0)
+                return result;
+
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	unregister_netdev(&cops0_dev);
+	if(cops0_dev.priv)
+                kfree_s(cops0_dev.priv, sizeof(struct cops_local));
+	if(cops0_dev.irq)
+		free_irq(cops0_dev.irq, &cops0_dev);
+        release_region(cops0_dev.base_addr, COPS_IO_EXTENT);
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
+ *  c-basic-offset: 4
+ *  c-file-offsets: ((substatement-open . 0))
+ * End:
+ */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops.h linux/drivers/net/appletalk/cops.h
--- v2.3.49/linux/drivers/net/appletalk/cops.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/cops.h	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,60 @@
+/*      cops.h: LocalTalk driver for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ */
+
+#ifndef __LINUX_COPSLTALK_H
+#define __LINUX_COPSLTALK_H
+
+#ifdef __KERNEL__
+
+/* Max LLAP size we will accept. */
+#define MAX_LLAP_SIZE		603
+
+/* Tangent */
+#define TANG_CARD_STATUS        1
+#define TANG_CLEAR_INT          1
+#define TANG_RESET              3
+
+#define TANG_TX_READY           1
+#define TANG_RX_READY           2
+
+/* Dayna */
+#define DAYNA_CMD_DATA          0
+#define DAYNA_CLEAR_INT         1
+#define DAYNA_CARD_STATUS       2
+#define DAYNA_INT_CARD          3
+#define DAYNA_RESET             4
+
+#define DAYNA_RX_READY          0
+#define DAYNA_TX_READY          1
+#define DAYNA_RX_REQUEST        3
+
+/* Same on both card types */
+#define COPS_CLEAR_INT  1
+
+/* LAP response codes received from the cards. */
+#define LAP_INIT        1       /* Init cmd */
+#define LAP_INIT_RSP    2       /* Init response */
+#define LAP_WRITE       3       /* Write cmd */
+#define DATA_READ       4       /* Data read */
+#define LAP_RESPONSE    4       /* Received ALAP frame response */
+#define LAP_GETSTAT     5       /* Get LAP and HW status */
+#define LAP_RSPSTAT     6       /* Status response */
+
+#endif
+
+/*
+ *	Structure to hold the firmware information.
+ */
+struct ltfirmware
+{
+        unsigned int length;
+        unsigned char * data;
+};
+
+#define DAYNA 1
+#define TANGENT 2
+
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops_ffdrv.h linux/drivers/net/appletalk/cops_ffdrv.h
--- v2.3.49/linux/drivers/net/appletalk/cops_ffdrv.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/cops_ffdrv.h	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,533 @@
+
+/*
+ *	The firmware this driver downloads into the Localtalk card is a
+ *	separate program and is not GPL'd source code, even though the Linux
+ *	side driver and the routine that loads this data into the card are.
+ *	
+ *	It is taken from the COPS SDK and is under the following license
+ *
+ *	This material is licensed to you strictly for use in conjunction with
+ *	the use of COPS LocalTalk adapters.
+ *	There is no charge for this SDK. And no waranty express or implied
+ *	about its fitness for any purpose. However, we will cheerefully
+ *	refund every penny you paid for this SDK...
+ *	Regards,
+ *
+ *	Thomas F. Divine
+ *	Chief Scientist
+ */
+
+
+/*      cops_ffdrv.h: LocalTalk driver firmware dump for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_COPS_DAYNA
+
+unsigned char ffdrv_code[] = {
+	58,3,0,50,228,149,33,255,255,34,226,149,
+	249,17,40,152,33,202,154,183,237,82,77,68,
+	11,107,98,19,54,0,237,176,175,50,80,0,
+	62,128,237,71,62,32,237,57,51,62,12,237,
+	57,50,237,57,54,62,6,237,57,52,62,12,
+	237,57,49,33,107,137,34,32,128,33,83,130,
+	34,40,128,33,86,130,34,42,128,33,112,130,
+	34,36,128,33,211,130,34,38,128,62,0,237,
+	57,16,33,63,148,34,34,128,237,94,205,15,
+	130,251,205,168,145,24,141,67,111,112,121,114,
+	105,103,104,116,32,40,67,41,32,49,57,56,
+	56,32,45,32,68,97,121,110,97,32,67,111,
+	109,109,117,110,105,99,97,116,105,111,110,115,
+	32,32,32,65,108,108,32,114,105,103,104,116,
+	115,32,114,101,115,101,114,118,101,100,46,32,
+	32,40,68,40,68,7,16,8,34,7,22,6,
+	16,5,12,4,8,3,6,140,0,16,39,128,
+	0,4,96,10,224,6,0,7,126,2,64,11,
+	118,12,6,13,0,14,193,15,0,5,96,3,
+	192,1,64,9,8,62,9,211,66,62,192,211,
+	66,62,100,61,32,253,6,28,33,205,129,14,
+	66,237,163,194,253,129,6,28,33,205,129,14,
+	64,237,163,194,9,130,201,62,47,50,71,152,
+	62,47,211,68,58,203,129,237,57,20,58,204,
+	129,237,57,21,33,77,152,54,132,205,233,129,
+	58,228,149,254,209,40,6,56,4,62,0,24,
+	2,219,96,33,233,149,119,230,62,33,232,149,
+	119,213,33,8,152,17,7,0,25,119,19,25,
+	119,209,201,251,237,77,245,197,213,229,221,229,
+	205,233,129,62,1,50,106,137,205,158,139,221,
+	225,225,209,193,241,251,237,77,245,197,213,219,
+	72,237,56,16,230,46,237,57,16,237,56,12,
+	58,72,152,183,32,26,6,20,17,128,2,237,
+	56,46,187,32,35,237,56,47,186,32,29,219,
+	72,230,1,32,3,5,32,232,175,50,72,152,
+	229,221,229,62,1,50,106,137,205,158,139,221,
+	225,225,24,25,62,1,50,72,152,58,201,129,
+	237,57,12,58,202,129,237,57,13,237,56,16,
+	246,17,237,57,16,209,193,241,251,237,77,245,
+	197,229,213,221,229,237,56,16,230,17,237,57,
+	16,237,56,20,58,34,152,246,16,246,8,211,
+	68,62,6,61,32,253,58,34,152,246,8,211,
+	68,58,203,129,237,57,20,58,204,129,237,57,
+	21,237,56,16,246,34,237,57,16,221,225,209,
+	225,193,241,251,237,77,33,2,0,57,126,230,
+	3,237,100,1,40,2,246,128,230,130,245,62,
+	5,211,64,241,211,64,201,229,213,243,237,56,
+	16,230,46,237,57,16,237,56,12,251,70,35,
+	35,126,254,175,202,77,133,254,129,202,15,133,
+	230,128,194,191,132,43,58,44,152,119,33,76,
+	152,119,35,62,132,119,120,254,255,40,4,58,
+	49,152,119,219,72,43,43,112,17,3,0,237,
+	56,52,230,248,237,57,52,219,72,230,1,194,
+	141,131,209,225,237,56,52,246,6,237,57,52,
+	62,1,55,251,201,62,3,211,66,62,192,211,
+	66,62,48,211,66,0,0,219,66,230,1,40,
+	4,219,67,24,240,205,203,135,58,75,152,254,
+	255,202,128,132,58,49,152,254,161,250,207,131,
+	58,34,152,211,68,62,10,211,66,62,128,211,
+	66,62,11,211,66,62,6,211,66,24,0,62,
+	14,211,66,62,33,211,66,62,1,211,66,62,
+	64,211,66,62,3,211,66,62,209,211,66,62,
+	100,71,219,66,230,1,32,6,5,32,247,195,
+	248,132,219,67,71,58,44,152,184,194,248,132,
+	62,100,71,219,66,230,1,32,6,5,32,247,
+	195,248,132,219,67,62,100,71,219,66,230,1,
+	32,6,5,32,247,195,248,132,219,67,254,133,
+	32,7,62,0,50,74,152,24,17,254,173,32,
+	7,62,1,50,74,152,24,6,254,141,194,248,
+	132,71,209,225,58,49,152,254,132,32,10,62,
+	50,205,2,134,205,144,135,24,27,254,140,32,
+	15,62,110,205,2,134,62,141,184,32,5,205,
+	144,135,24,8,62,10,205,2,134,205,8,134,
+	62,1,50,106,137,205,158,139,237,56,52,246,
+	6,237,57,52,175,183,251,201,62,20,135,237,
+	57,20,175,237,57,21,237,56,16,246,2,237,
+	57,16,237,56,20,95,237,56,21,123,254,10,
+	48,244,237,56,16,230,17,237,57,16,209,225,
+	205,144,135,62,1,50,106,137,205,158,139,237,
+	56,52,246,6,237,57,52,175,183,251,201,209,
+	225,243,219,72,230,1,40,13,62,10,211,66,
+	0,0,219,66,230,192,202,226,132,237,56,52,
+	246,6,237,57,52,62,1,55,251,201,205,203,
+	135,62,1,50,106,137,205,158,139,237,56,52,
+	246,6,237,57,52,183,251,201,209,225,62,1,
+	50,106,137,205,158,139,237,56,52,246,6,237,
+	57,52,62,2,55,251,201,209,225,243,219,72,
+	230,1,202,213,132,62,10,211,66,0,0,219,
+	66,230,192,194,213,132,229,62,1,50,106,137,
+	42,40,152,205,65,143,225,17,3,0,205,111,
+	136,62,6,211,66,58,44,152,211,66,237,56,
+	52,246,6,237,57,52,183,251,201,209,197,237,
+	56,52,230,248,237,57,52,219,72,230,1,32,
+	15,193,225,237,56,52,246,6,237,57,52,62,
+	1,55,251,201,14,23,58,37,152,254,0,40,
+	14,14,2,254,1,32,5,62,140,119,24,3,
+	62,132,119,43,43,197,205,203,135,193,62,1,
+	211,66,62,64,211,66,62,3,211,66,62,193,
+	211,66,62,100,203,39,71,219,66,230,1,32,
+	6,5,32,247,195,229,133,33,238,151,219,67,
+	71,58,44,152,184,194,229,133,119,62,100,71,
+	219,66,230,1,32,6,5,32,247,195,229,133,
+	219,67,35,119,13,32,234,193,225,62,1,50,
+	106,137,205,158,139,237,56,52,246,6,237,57,
+	52,175,183,251,201,33,234,151,35,35,62,255,
+	119,193,225,62,1,50,106,137,205,158,139,237,
+	56,52,246,6,237,57,52,175,251,201,243,61,
+	32,253,251,201,62,3,211,66,62,192,211,66,
+	58,49,152,254,140,32,19,197,229,213,17,181,
+	129,33,185,129,1,2,0,237,176,209,225,193,
+	24,27,229,213,33,187,129,58,49,152,230,15,
+	87,30,2,237,92,25,17,181,129,126,18,19,
+	35,126,18,209,225,58,34,152,246,8,211,68,
+	58,49,152,254,165,40,14,254,164,40,10,62,
+	10,211,66,62,224,211,66,24,25,58,74,152,
+	254,0,40,10,62,10,211,66,62,160,211,66,
+	24,8,62,10,211,66,62,128,211,66,62,11,
+	211,66,62,6,211,66,205,147,143,62,5,211,
+	66,62,224,211,66,62,5,211,66,62,96,211,
+	66,62,5,61,32,253,62,5,211,66,62,224,
+	211,66,62,14,61,32,253,62,5,211,66,62,
+	233,211,66,62,128,211,66,58,181,129,61,32,
+	253,62,1,211,66,62,192,211,66,1,254,19,
+	237,56,46,187,32,6,13,32,247,195,226,134,
+	62,192,211,66,0,0,219,66,203,119,40,250,
+	219,66,203,87,40,250,243,237,56,16,230,17,
+	237,57,16,237,56,20,251,62,5,211,66,62,
+	224,211,66,58,182,129,61,32,253,229,33,181,
+	129,58,183,129,203,63,119,35,58,184,129,119,
+	225,62,10,211,66,62,224,211,66,62,11,211,
+	66,62,118,211,66,62,47,211,68,62,5,211,
+	66,62,233,211,66,58,181,129,61,32,253,62,
+	5,211,66,62,224,211,66,58,182,129,61,32,
+	253,62,5,211,66,62,96,211,66,201,229,213,
+	58,50,152,230,15,87,30,2,237,92,33,187,
+	129,25,17,181,129,126,18,35,19,126,18,209,
+	225,58,71,152,246,8,211,68,58,50,152,254,
+	165,40,14,254,164,40,10,62,10,211,66,62,
+	224,211,66,24,8,62,10,211,66,62,128,211,
+	66,62,11,211,66,62,6,211,66,195,248,135,
+	62,3,211,66,62,192,211,66,197,229,213,17,
+	181,129,33,183,129,1,2,0,237,176,209,225,
+	193,62,47,211,68,62,10,211,66,62,224,211,
+	66,62,11,211,66,62,118,211,66,62,1,211,
+	66,62,0,211,66,205,147,143,195,16,136,62,
+	3,211,66,62,192,211,66,197,229,213,17,181,
+	129,33,183,129,1,2,0,237,176,209,225,193,
+	62,47,211,68,62,10,211,66,62,224,211,66,
+	62,11,211,66,62,118,211,66,205,147,143,62,
+	5,211,66,62,224,211,66,62,5,211,66,62,
+	96,211,66,62,5,61,32,253,62,5,211,66,
+	62,224,211,66,62,14,61,32,253,62,5,211,
+	66,62,233,211,66,62,128,211,66,58,181,129,
+	61,32,253,62,1,211,66,62,192,211,66,1,
+	254,19,237,56,46,187,32,6,13,32,247,195,
+	88,136,62,192,211,66,0,0,219,66,203,119,
+	40,250,219,66,203,87,40,250,62,5,211,66,
+	62,224,211,66,58,182,129,61,32,253,62,5,
+	211,66,62,96,211,66,201,197,14,67,6,0,
+	62,3,211,66,62,192,211,66,62,48,211,66,
+	0,0,219,66,230,1,40,4,219,67,24,240,
+	62,5,211,66,62,233,211,66,62,128,211,66,
+	58,181,129,61,32,253,237,163,29,62,192,211,
+	66,219,66,230,4,40,250,237,163,29,32,245,
+	219,66,230,4,40,250,62,255,71,219,66,230,
+	4,40,3,5,32,247,219,66,230,4,40,250,
+	62,5,211,66,62,224,211,66,58,182,129,61,
+	32,253,62,5,211,66,62,96,211,66,58,71,
+	152,254,1,202,18,137,62,16,211,66,62,56,
+	211,66,62,14,211,66,62,33,211,66,62,1,
+	211,66,62,248,211,66,237,56,48,246,153,230,
+	207,237,57,48,62,3,211,66,62,221,211,66,
+	193,201,58,71,152,211,68,62,10,211,66,62,
+	128,211,66,62,11,211,66,62,6,211,66,62,
+	6,211,66,58,44,152,211,66,62,16,211,66,
+	62,56,211,66,62,48,211,66,0,0,62,14,
+	211,66,62,33,211,66,62,1,211,66,62,248,
+	211,66,237,56,48,246,145,246,8,230,207,237,
+	57,48,62,3,211,66,62,221,211,66,193,201,
+	44,3,1,0,70,69,1,245,197,213,229,175,
+	50,72,152,237,56,16,230,46,237,57,16,237,
+	56,12,62,1,211,66,0,0,219,66,95,230,
+	160,32,3,195,20,139,123,230,96,194,72,139,
+	62,48,211,66,62,1,211,66,62,64,211,66,
+	237,91,40,152,205,207,143,25,43,55,237,82,
+	218,70,139,34,42,152,98,107,58,44,152,190,
+	194,210,138,35,35,62,130,190,194,200,137,62,
+	1,50,48,152,62,175,190,202,82,139,62,132,
+	190,32,44,50,50,152,62,47,50,71,152,229,
+	175,50,106,137,42,40,152,205,65,143,225,54,
+	133,43,70,58,44,152,119,43,112,17,3,0,
+	62,10,205,2,134,205,111,136,195,158,138,62,
+	140,190,32,19,50,50,152,58,233,149,230,4,
+	202,222,138,62,1,50,71,152,195,219,137,126,
+	254,160,250,185,138,254,166,242,185,138,50,50,
+	152,43,126,35,229,213,33,234,149,95,22,0,
+	25,126,254,132,40,18,254,140,40,14,58,50,
+	152,230,15,87,126,31,21,242,65,138,56,2,
+	175,119,58,50,152,230,15,87,58,233,149,230,
+	62,31,21,242,85,138,218,98,138,209,225,195,
+	20,139,58,50,152,33,100,137,230,15,95,22,
+	0,25,126,50,71,152,209,225,58,50,152,254,
+	164,250,135,138,58,73,152,254,0,40,4,54,
+	173,24,2,54,133,43,70,58,44,152,119,43,
+	112,17,3,0,205,70,135,175,50,106,137,205,
+	208,139,58,199,129,237,57,12,58,200,129,237,
+	57,13,237,56,16,246,17,237,57,16,225,209,
+	193,241,251,237,77,62,129,190,194,227,138,54,
+	130,43,70,58,44,152,119,43,112,17,3,0,
+	205,144,135,195,20,139,35,35,126,254,132,194,
+	227,138,175,50,106,137,205,158,139,24,42,58,
+	201,154,254,1,40,7,62,1,50,106,137,24,
+	237,58,106,137,254,1,202,222,138,62,128,166,
+	194,222,138,221,229,221,33,67,152,205,127,142,
+	205,109,144,221,225,225,209,193,241,251,237,77,
+	58,106,137,254,1,202,44,139,58,50,152,254,
+	164,250,44,139,58,73,152,238,1,50,73,152,
+	221,229,221,33,51,152,205,127,142,221,225,62,
+	1,50,106,137,205,158,139,195,13,139,24,208,
+	24,206,24,204,230,64,40,3,195,20,139,195,
+	20,139,43,126,33,8,152,119,35,58,44,152,
+	119,43,237,91,35,152,205,203,135,205,158,139,
+	195,13,139,175,50,78,152,62,3,211,66,62,
+	192,211,66,201,197,33,4,0,57,126,35,102,
+	111,62,1,50,106,137,219,72,205,141,139,193,
+	201,62,1,50,78,152,34,40,152,54,0,35,
+	35,54,0,195,163,139,58,78,152,183,200,229,
+	33,181,129,58,183,129,119,35,58,184,129,119,
+	225,62,47,211,68,62,14,211,66,62,193,211,
+	66,62,10,211,66,62,224,211,66,62,11,211,
+	66,62,118,211,66,195,3,140,58,78,152,183,
+	200,58,71,152,211,68,254,69,40,4,254,70,
+	32,17,58,73,152,254,0,40,10,62,10,211,
+	66,62,160,211,66,24,8,62,10,211,66,62,
+	128,211,66,62,11,211,66,62,6,211,66,62,
+	6,211,66,58,44,152,211,66,62,16,211,66,
+	62,56,211,66,62,48,211,66,0,0,219,66,
+	230,1,40,4,219,67,24,240,62,14,211,66,
+	62,33,211,66,42,40,152,205,65,143,62,1,
+	211,66,62,248,211,66,237,56,48,246,145,246,
+	8,230,207,237,57,48,62,3,211,66,62,221,
+	211,66,201,62,16,211,66,62,56,211,66,62,
+	48,211,66,0,0,219,66,230,1,40,4,219,
+	67,24,240,62,14,211,66,62,33,211,66,62,
+	1,211,66,62,248,211,66,237,56,48,246,153,
+	230,207,237,57,48,62,3,211,66,62,221,211,
+	66,201,229,213,33,234,149,95,22,0,25,126,
+	254,132,40,4,254,140,32,2,175,119,123,209,
+	225,201,6,8,14,0,31,48,1,12,16,250,
+	121,201,33,4,0,57,94,35,86,33,2,0,
+	57,126,35,102,111,221,229,34,89,152,237,83,
+	91,152,221,33,63,152,205,127,142,58,81,152,
+	50,82,152,58,80,152,135,50,80,152,205,162,
+	140,254,3,56,16,58,81,152,135,60,230,15,
+	50,81,152,175,50,80,152,24,23,58,79,152,
+	205,162,140,254,3,48,13,58,81,152,203,63,
+	50,81,152,62,255,50,79,152,58,81,152,50,
+	82,152,58,79,152,135,50,79,152,62,32,50,
+	83,152,50,84,152,237,56,16,230,17,237,57,
+	16,219,72,62,192,50,93,152,62,93,50,94,
+	152,58,93,152,61,50,93,152,32,9,58,94,
+	152,61,50,94,152,40,44,62,170,237,57,20,
+	175,237,57,21,237,56,16,246,2,237,57,16,
+	219,72,230,1,202,29,141,237,56,20,71,237,
+	56,21,120,254,10,48,237,237,56,16,230,17,
+	237,57,16,243,62,14,211,66,62,65,211,66,
+	251,58,39,152,23,23,60,50,39,152,71,58,
+	82,152,160,230,15,40,22,71,14,10,219,66,
+	230,16,202,186,141,219,72,230,1,202,186,141,
+	13,32,239,16,235,42,89,152,237,91,91,152,
+	205,47,131,48,7,61,202,186,141,195,227,141,
+	221,225,33,0,0,201,221,33,55,152,205,127,
+	142,58,84,152,61,50,84,152,40,19,58,82,
+	152,246,1,50,82,152,58,79,152,246,1,50,
+	79,152,195,29,141,221,225,33,1,0,201,221,
+	33,59,152,205,127,142,58,80,152,246,1,50,
+	80,152,58,82,152,135,246,1,50,82,152,58,
+	83,152,61,50,83,152,194,29,141,221,225,33,
+	2,0,201,221,229,33,0,0,57,17,4,0,
+	25,126,50,44,152,230,128,50,85,152,58,85,
+	152,183,40,6,221,33,88,2,24,4,221,33,
+	150,0,58,44,152,183,40,53,60,40,50,60,
+	40,47,61,61,33,86,152,119,35,119,35,54,
+	129,175,50,48,152,221,43,221,229,225,124,181,
+	40,42,33,86,152,17,3,0,205,189,140,17,
+	232,3,27,123,178,32,251,58,48,152,183,40,
+	224,58,44,152,71,62,7,128,230,127,71,58,
+	85,152,176,50,44,152,24,162,221,225,201,183,
+	221,52,0,192,221,52,1,192,221,52,2,192,
+	221,52,3,192,55,201,245,62,1,211,100,241,
+	201,245,62,1,211,96,241,201,33,2,0,57,
+	126,35,102,111,237,56,48,230,175,237,57,48,
+	62,48,237,57,49,125,237,57,32,124,237,57,
+	33,62,0,237,57,34,62,88,237,57,35,62,
+	0,237,57,36,237,57,37,33,128,2,125,237,
+	57,38,124,237,57,39,237,56,48,246,97,230,
+	207,237,57,48,62,0,237,57,0,62,0,211,
+	96,211,100,201,33,2,0,57,126,35,102,111,
+	237,56,48,230,175,237,57,48,62,12,237,57,
+	49,62,76,237,57,32,62,0,237,57,33,237,
+	57,34,125,237,57,35,124,237,57,36,62,0,
+	237,57,37,33,128,2,125,237,57,38,124,237,
+	57,39,237,56,48,246,97,230,207,237,57,48,
+	62,1,211,96,201,33,2,0,57,126,35,102,
+	111,229,237,56,48,230,87,237,57,48,125,237,
+	57,40,124,237,57,41,62,0,237,57,42,62,
+	67,237,57,43,62,0,237,57,44,58,106,137,
+	254,1,32,5,33,6,0,24,3,33,128,2,
+	125,237,57,46,124,237,57,47,237,56,50,230,
+	252,246,2,237,57,50,225,201,33,4,0,57,
+	94,35,86,33,2,0,57,126,35,102,111,237,
+	56,48,230,87,237,57,48,125,237,57,40,124,
+	237,57,41,62,0,237,57,42,62,67,237,57,
+	43,62,0,237,57,44,123,237,57,46,122,237,
+	57,47,237,56,50,230,244,246,0,237,57,50,
+	237,56,48,246,145,230,207,237,57,48,201,213,
+	237,56,46,95,237,56,47,87,237,56,46,111,
+	237,56,47,103,183,237,82,32,235,33,128,2,
+	183,237,82,209,201,213,237,56,38,95,237,56,
+	39,87,237,56,38,111,237,56,39,103,183,237,
+	82,32,235,33,128,2,183,237,82,209,201,245,
+	197,1,52,0,237,120,230,253,237,121,193,241,
+	201,245,197,1,52,0,237,120,246,2,237,121,
+	193,241,201,33,2,0,57,126,35,102,111,126,
+	35,110,103,201,33,0,0,34,102,152,34,96,
+	152,34,98,152,33,202,154,34,104,152,237,91,
+	104,152,42,226,149,183,237,82,17,0,255,25,
+	34,100,152,203,124,40,6,33,0,125,34,100,
+	152,42,104,152,35,35,35,229,205,120,139,193,
+	201,205,186,149,229,42,40,152,35,35,35,229,
+	205,39,144,193,124,230,3,103,221,117,254,221,
+	116,255,237,91,42,152,35,35,35,183,237,82,
+	32,12,17,5,0,42,42,152,205,171,149,242,
+	169,144,42,40,152,229,205,120,139,193,195,198,
+	149,237,91,42,152,42,98,152,25,34,98,152,
+	19,19,19,42,102,152,25,34,102,152,237,91,
+	100,152,33,158,253,25,237,91,102,152,205,171,
+	149,242,214,144,33,0,0,34,102,152,62,1,
+	50,95,152,205,225,144,195,198,149,58,95,152,
+	183,200,237,91,96,152,42,102,152,205,171,149,
+	242,5,145,237,91,102,152,33,98,2,25,237,
+	91,96,152,205,171,149,250,37,145,237,91,96,
+	152,42,102,152,183,237,82,32,7,42,98,152,
+	125,180,40,13,237,91,102,152,42,96,152,205,
+	171,149,242,58,145,237,91,104,152,42,102,152,
+	25,35,35,35,229,205,120,139,193,175,50,95,
+	152,201,195,107,139,205,206,149,250,255,243,205,
+	225,144,251,58,230,149,183,194,198,149,17,1,
+	0,42,98,152,205,171,149,250,198,149,62,1,
+	50,230,149,237,91,96,152,42,104,152,25,221,
+	117,252,221,116,253,237,91,104,152,42,96,152,
+	25,35,35,35,221,117,254,221,116,255,35,35,
+	35,229,205,39,144,124,230,3,103,35,35,35,
+	221,117,250,221,116,251,235,221,110,252,221,102,
+	253,115,35,114,35,54,4,62,1,211,100,211,
+	84,195,198,149,33,0,0,34,102,152,34,96,
+	152,34,98,152,33,202,154,34,104,152,237,91,
+	104,152,42,226,149,183,237,82,17,0,255,25,
+	34,100,152,33,109,152,54,0,33,107,152,229,
+	205,240,142,193,62,47,50,34,152,62,132,50,
+	49,152,205,241,145,205,61,145,58,39,152,60,
+	50,39,152,24,241,205,206,149,251,255,33,109,
+	152,126,183,202,198,149,110,221,117,251,33,109,
+	152,54,0,221,126,251,254,1,40,28,254,3,
+	40,101,254,4,202,190,147,254,5,202,147,147,
+	254,8,40,87,33,107,152,229,205,240,142,195,
+	198,149,58,201,154,183,32,21,33,111,152,126,
+	50,229,149,205,52,144,33,110,152,110,38,0,
+	229,205,11,142,193,237,91,96,152,42,104,152,
+	25,221,117,254,221,116,255,35,35,54,2,17,
+	2,0,43,43,115,35,114,58,44,152,35,35,
+	119,58,228,149,35,119,62,1,211,100,211,84,
+	62,1,50,201,154,24,169,205,153,142,58,231,
+	149,183,40,250,175,50,231,149,33,110,152,126,
+	254,255,40,91,58,233,149,230,63,183,40,83,
+	94,22,0,33,234,149,25,126,183,40,13,33,
+	110,152,94,33,234,150,25,126,254,3,32,36,
+	205,81,148,125,180,33,110,152,94,22,0,40,
+	17,33,234,149,25,54,0,33,107,152,229,205,
+	240,142,193,195,198,149,33,234,150,25,54,0,
+	33,110,152,94,22,0,33,234,149,25,126,50,
+	49,152,254,132,32,37,62,47,50,34,152,42,
+	107,152,229,33,110,152,229,205,174,140,193,193,
+	125,180,33,110,152,94,22,0,33,234,150,202,
+	117,147,25,52,195,120,147,58,49,152,254,140,
+	32,7,62,1,50,34,152,24,210,62,32,50,
+	106,152,24,19,58,49,152,95,58,106,152,163,
+	183,58,106,152,32,11,203,63,50,106,152,58,
+	106,152,183,32,231,254,2,40,51,254,4,40,
+	38,254,8,40,26,254,16,40,13,254,32,32,
+	158,62,165,50,49,152,62,69,24,190,62,164,
+	50,49,152,62,70,24,181,62,163,50,49,152,
+	175,24,173,62,162,50,49,152,62,1,24,164,
+	62,161,50,49,152,62,3,24,155,25,54,0,
+	221,126,251,254,8,40,7,58,230,149,183,202,
+	32,146,33,107,152,229,205,240,142,193,211,84,
+	195,198,149,237,91,96,152,42,104,152,25,221,
+	117,254,221,116,255,35,35,54,6,17,2,0,
+	43,43,115,35,114,58,228,149,35,35,119,58,
+	233,149,35,119,205,146,142,195,32,146,237,91,
+	96,152,42,104,152,25,229,205,160,142,193,58,
+	231,149,183,40,250,175,50,231,149,243,237,91,
+	96,152,42,104,152,25,221,117,254,221,116,255,
+	78,35,70,221,113,252,221,112,253,89,80,42,
+	98,152,183,237,82,34,98,152,203,124,40,19,
+	33,0,0,34,98,152,34,102,152,34,96,152,
+	62,1,50,95,152,24,40,221,94,252,221,86,
+	253,19,19,19,42,96,152,25,34,96,152,237,
+	91,100,152,33,158,253,25,237,91,96,152,205,
+	171,149,242,55,148,33,0,0,34,96,152,175,
+	50,230,149,251,195,32,146,245,62,1,50,231,
+	149,62,16,237,57,0,211,80,241,251,237,77,
+	201,205,186,149,229,229,33,0,0,34,37,152,
+	33,110,152,126,50,234,151,58,44,152,33,235,
+	151,119,221,54,253,0,221,54,254,0,195,230,
+	148,33,236,151,54,175,33,3,0,229,33,234,
+	151,229,205,174,140,193,193,33,236,151,126,254,
+	255,40,74,33,245,151,110,221,117,255,33,249,
+	151,126,221,166,255,221,119,255,33,253,151,126,
+	221,166,255,221,119,255,58,232,149,95,221,126,
+	255,163,221,119,255,183,40,15,230,191,33,110,
+	152,94,22,0,33,234,149,25,119,24,12,33,
+	110,152,94,22,0,33,234,149,25,54,132,33,
+	0,0,195,198,149,221,110,253,221,102,254,35,
+	221,117,253,221,116,254,17,32,0,221,110,253,
+	221,102,254,205,171,149,250,117,148,58,233,149,
+	203,87,40,84,33,1,0,34,37,152,221,54,
+	253,0,221,54,254,0,24,53,33,236,151,54,
+	175,33,3,0,229,33,234,151,229,205,174,140,
+	193,193,33,236,151,126,254,255,40,14,33,110,
+	152,94,22,0,33,234,149,25,54,140,24,159,
+	221,110,253,221,102,254,35,221,117,253,221,116,
+	254,17,32,0,221,110,253,221,102,254,205,171,
+	149,250,12,149,33,2,0,34,37,152,221,54,
+	253,0,221,54,254,0,24,54,33,236,151,54,
+	175,33,3,0,229,33,234,151,229,205,174,140,
+	193,193,33,236,151,126,254,255,40,15,33,110,
+	152,94,22,0,33,234,149,25,54,132,195,211,
+	148,221,110,253,221,102,254,35,221,117,253,221,
+	116,254,17,32,0,221,110,253,221,102,254,205,
+	171,149,250,96,149,33,1,0,195,198,149,124,
+	170,250,179,149,237,82,201,124,230,128,237,82,
+	60,201,225,253,229,221,229,221,33,0,0,221,
+	57,233,221,249,221,225,253,225,201,233,225,253,
+	229,221,229,221,33,0,0,221,57,94,35,86,
+	35,235,57,249,235,233,0,0,0,0,0,0,
+	62,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,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,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,
+	175,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,133,1,0,0,0,63,
+	255,255,255,255,0,0,0,63,0,0,0,0,
+	0,0,0,0,0,0,0,24,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
+	} ;
+
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops_ltdrv.h linux/drivers/net/appletalk/cops_ltdrv.h
--- v2.3.49/linux/drivers/net/appletalk/cops_ltdrv.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/cops_ltdrv.h	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,242 @@
+/*
+ *	The firmware this driver downloads into the Localtalk card is a
+ *	separate program and is not GPL'd source code, even though the Linux
+ *	side driver and the routine that loads this data into the card are.
+ *	
+ *	It is taken from the COPS SDK and is under the following license
+ *
+ *	This material is licensed to you strictly for use in conjunction with
+ *	the use of COPS LocalTalk adapters.
+ *	There is no charge for this SDK. And no waranty express or implied
+ *	about its fitness for any purpose. However, we will cheerefully
+ *	refund every penny you paid for this SDK...
+ *	Regards,
+ *
+ *	Thomas F. Divine
+ *	Chief Scientist
+ */
+
+
+/*      cops_ltdrv.h: LocalTalk driver firmware dump for Linux.
+ *
+ *      Authors:
+ *      - Jay Schulist <jschlst@turbolinux.com>
+ */
+ 
+#include <linux/config.h>
+
+#ifdef CONFIG_COPS_TANGENT
+
+unsigned char ltdrv_code[] = {
+	58,3,0,50,148,10,33,143,15,62,85,119,
+	190,32,9,62,170,119,190,32,3,35,24,241,
+	34,146,10,249,17,150,10,33,143,15,183,237,
+	82,77,68,11,107,98,19,54,0,237,176,62,
+	16,237,57,51,62,0,237,57,50,237,57,54,
+	62,12,237,57,49,62,195,33,39,2,50,56,
+	0,34,57,0,237,86,205,30,2,251,205,60,
+	10,24,169,67,111,112,121,114,105,103,104,116,
+	32,40,99,41,32,49,57,56,56,45,49,57,
+	57,50,44,32,80,114,105,110,116,105,110,103,
+	32,67,111,109,109,117,110,105,99,97,116,105,
+	111,110,115,32,65,115,115,111,99,105,97,116,
+	101,115,44,32,73,110,99,46,65,108,108,32,
+	114,105,103,104,116,115,32,114,101,115,101,114,
+	118,101,100,46,32,32,4,4,22,40,255,60,
+	4,96,10,224,6,0,7,126,2,64,11,246,
+	12,6,13,0,14,193,15,0,5,96,3,192,
+	1,0,9,8,62,3,211,82,62,192,211,82,
+	201,62,3,211,82,62,213,211,82,201,62,5,
+	211,82,62,224,211,82,201,62,5,211,82,62,
+	224,211,82,201,62,5,211,82,62,96,211,82,
+	201,6,28,33,180,1,14,82,237,163,194,4,
+	2,33,39,2,34,64,0,58,3,0,230,1,
+	192,62,11,237,121,62,118,237,121,201,33,182,
+	10,54,132,205,253,1,201,245,197,213,229,42,
+	150,10,14,83,17,98,2,67,20,237,162,58,
+	179,1,95,219,82,230,1,32,6,29,32,247,
+	195,17,3,62,1,211,82,219,82,95,230,160,
+	32,10,237,162,32,225,21,32,222,195,15,3,
+	237,162,123,230,96,194,21,3,62,48,211,82,
+	62,1,211,82,175,211,82,237,91,150,10,43,
+	55,237,82,218,19,3,34,152,10,98,107,58,
+	154,10,190,32,81,62,1,50,158,10,35,35,
+	62,132,190,32,44,54,133,43,70,58,154,10,
+	119,43,112,17,3,0,205,137,3,62,16,211,
+	82,62,56,211,82,205,217,1,42,150,10,14,
+	83,17,98,2,67,20,58,178,1,95,195,59,
+	2,62,129,190,194,227,2,54,130,43,70,58,
+	154,10,119,43,112,17,3,0,205,137,3,195,
+	254,2,35,35,126,254,132,194,227,2,205,61,
+	3,24,20,62,128,166,194,222,2,221,229,221,
+	33,175,10,205,93,6,205,144,7,221,225,225,
+	209,193,241,251,237,77,221,229,221,33,159,10,
+	205,93,6,221,225,205,61,3,195,247,2,24,
+	237,24,235,24,233,230,64,40,2,24,227,24,
+	225,175,50,179,10,205,208,1,201,197,33,4,
+	0,57,126,35,102,111,205,51,3,193,201,62,
+	1,50,179,10,34,150,10,54,0,58,179,10,
+	183,200,62,14,211,82,62,193,211,82,62,10,
+	211,82,62,224,211,82,62,6,211,82,58,154,
+	10,211,82,62,16,211,82,62,56,211,82,62,
+	48,211,82,219,82,230,1,40,4,219,83,24,
+	242,62,14,211,82,62,33,211,82,62,1,211,
+	82,62,9,211,82,62,32,211,82,205,217,1,
+	201,14,83,205,208,1,24,23,14,83,205,208,
+	1,205,226,1,58,174,1,61,32,253,205,244,
+	1,58,174,1,61,32,253,205,226,1,58,175,
+	1,61,32,253,62,5,211,82,62,233,211,82,
+	62,128,211,82,58,176,1,61,32,253,237,163,
+	27,62,192,211,82,219,82,230,4,40,250,237,
+	163,27,122,179,32,243,219,82,230,4,40,250,
+	58,178,1,71,219,82,230,4,40,3,5,32,
+	247,219,82,230,4,40,250,205,235,1,58,177,
+	1,61,32,253,205,244,1,201,229,213,35,35,
+	126,230,128,194,145,4,43,58,154,10,119,43,
+	70,33,181,10,119,43,112,17,3,0,243,62,
+	10,211,82,219,82,230,128,202,41,4,209,225,
+	62,1,55,251,201,205,144,3,58,180,10,254,
+	255,202,127,4,205,217,1,58,178,1,71,219,
+	82,230,1,32,6,5,32,247,195,173,4,219,
+	83,71,58,154,10,184,194,173,4,58,178,1,
+	71,219,82,230,1,32,6,5,32,247,195,173,
+	4,219,83,58,178,1,71,219,82,230,1,32,
+	6,5,32,247,195,173,4,219,83,254,133,194,
+	173,4,58,179,1,24,4,58,179,1,135,61,
+	32,253,209,225,205,137,3,205,61,3,183,251,
+	201,209,225,243,62,10,211,82,219,82,230,128,
+	202,164,4,62,1,55,251,201,205,144,3,205,
+	61,3,183,251,201,209,225,62,2,55,251,201,
+	243,62,14,211,82,62,33,211,82,251,201,33,
+	4,0,57,94,35,86,33,2,0,57,126,35,
+	102,111,221,229,34,193,10,237,83,195,10,221,
+	33,171,10,205,93,6,58,185,10,50,186,10,
+	58,184,10,135,50,184,10,205,112,6,254,3,
+	56,16,58,185,10,135,60,230,15,50,185,10,
+	175,50,184,10,24,23,58,183,10,205,112,6,
+	254,3,48,13,58,185,10,203,63,50,185,10,
+	62,255,50,183,10,58,185,10,50,186,10,58,
+	183,10,135,50,183,10,62,32,50,187,10,50,
+	188,10,6,255,219,82,230,16,32,3,5,32,
+	247,205,180,4,6,40,219,82,230,16,40,3,
+	5,32,247,62,10,211,82,219,82,230,128,194,
+	46,5,219,82,230,16,40,214,237,95,71,58,
+	186,10,160,230,15,40,32,71,14,10,62,10,
+	211,82,219,82,230,128,202,119,5,205,180,4,
+	195,156,5,219,82,230,16,202,156,5,13,32,
+	229,16,225,42,193,10,237,91,195,10,205,252,
+	3,48,7,61,202,156,5,195,197,5,221,225,
+	33,0,0,201,221,33,163,10,205,93,6,58,
+	188,10,61,50,188,10,40,19,58,186,10,246,
+	1,50,186,10,58,183,10,246,1,50,183,10,
+	195,46,5,221,225,33,1,0,201,221,33,167,
+	10,205,93,6,58,184,10,246,1,50,184,10,
+	58,186,10,135,246,1,50,186,10,58,187,10,
+	61,50,187,10,194,46,5,221,225,33,2,0,
+	201,221,229,33,0,0,57,17,4,0,25,126,
+	50,154,10,230,128,50,189,10,58,189,10,183,
+	40,6,221,33,88,2,24,4,221,33,150,0,
+	58,154,10,183,40,49,60,40,46,61,33,190,
+	10,119,35,119,35,54,129,175,50,158,10,221,
+	43,221,229,225,124,181,40,42,33,190,10,17,
+	3,0,205,206,4,17,232,3,27,123,178,32,
+	251,58,158,10,183,40,224,58,154,10,71,62,
+	7,128,230,127,71,58,189,10,176,50,154,10,
+	24,166,221,225,201,183,221,52,0,192,221,52,
+	1,192,221,52,2,192,221,52,3,192,55,201,
+	6,8,14,0,31,48,1,12,16,250,121,201,
+	33,2,0,57,94,35,86,35,78,35,70,35,
+	126,35,102,105,79,120,68,103,237,176,201,33,
+	2,0,57,126,35,102,111,62,17,237,57,48,
+	125,237,57,40,124,237,57,41,62,0,237,57,
+	42,62,64,237,57,43,62,0,237,57,44,33,
+	128,2,125,237,57,46,124,237,57,47,62,145,
+	237,57,48,211,68,58,149,10,211,66,201,33,
+	2,0,57,126,35,102,111,62,33,237,57,48,
+	62,64,237,57,32,62,0,237,57,33,237,57,
+	34,125,237,57,35,124,237,57,36,62,0,237,
+	57,37,33,128,2,125,237,57,38,124,237,57,
+	39,62,97,237,57,48,211,67,58,149,10,211,
+	66,201,237,56,46,95,237,56,47,87,237,56,
+	46,111,237,56,47,103,183,237,82,32,235,33,
+	128,2,183,237,82,201,237,56,38,95,237,56,
+	39,87,237,56,38,111,237,56,39,103,183,237,
+	82,32,235,33,128,2,183,237,82,201,205,106,
+	10,221,110,6,221,102,7,126,35,110,103,195,
+	118,10,205,106,10,33,0,0,34,205,10,34,
+	198,10,34,200,10,33,143,15,34,207,10,237,
+	91,207,10,42,146,10,183,237,82,17,0,255,
+	25,34,203,10,203,124,40,6,33,0,125,34,
+	203,10,42,207,10,229,205,37,3,195,118,10,
+	205,106,10,229,42,150,10,35,35,35,229,205,
+	70,7,193,124,230,3,103,221,117,254,221,116,
+	255,237,91,152,10,35,35,35,183,237,82,32,
+	12,17,5,0,42,152,10,205,91,10,242,203,
+	7,42,150,10,229,205,37,3,195,118,10,237,
+	91,152,10,42,200,10,25,34,200,10,42,205,
+	10,25,34,205,10,237,91,203,10,33,158,253,
+	25,237,91,205,10,205,91,10,242,245,7,33,
+	0,0,34,205,10,62,1,50,197,10,205,5,
+	8,33,0,0,57,249,195,118,10,205,106,10,
+	58,197,10,183,202,118,10,237,91,198,10,42,
+	205,10,205,91,10,242,46,8,237,91,205,10,
+	33,98,2,25,237,91,198,10,205,91,10,250,
+	78,8,237,91,198,10,42,205,10,183,237,82,
+	32,7,42,200,10,125,180,40,13,237,91,205,
+	10,42,198,10,205,91,10,242,97,8,237,91,
+	207,10,42,205,10,25,229,205,37,3,175,50,
+	197,10,195,118,10,205,29,3,33,0,0,57,
+	249,195,118,10,205,106,10,58,202,10,183,40,
+	22,205,14,7,237,91,209,10,19,19,19,205,
+	91,10,242,139,8,33,1,0,195,118,10,33,
+	0,0,195,118,10,205,126,10,252,255,205,108,
+	8,125,180,194,118,10,237,91,200,10,33,0,
+	0,205,91,10,242,118,10,237,91,207,10,42,
+	198,10,25,221,117,254,221,116,255,35,35,35,
+	229,205,70,7,193,124,230,3,103,35,35,35,
+	221,117,252,221,116,253,229,221,110,254,221,102,
+	255,229,33,212,10,229,205,124,6,193,193,221,
+	110,252,221,102,253,34,209,10,33,211,10,54,
+	4,33,209,10,227,205,147,6,193,62,1,50,
+	202,10,243,221,94,252,221,86,253,42,200,10,
+	183,237,82,34,200,10,203,124,40,17,33,0,
+	0,34,200,10,34,205,10,34,198,10,50,197,
+	10,24,37,221,94,252,221,86,253,42,198,10,
+	25,34,198,10,237,91,203,10,33,158,253,25,
+	237,91,198,10,205,91,10,242,68,9,33,0,
+	0,34,198,10,205,5,8,33,0,0,57,249,
+	251,195,118,10,205,106,10,33,49,13,126,183,
+	40,16,205,42,7,237,91,47,13,19,19,19,
+	205,91,10,242,117,9,58,142,15,198,1,50,
+	142,15,195,118,10,33,49,13,126,254,1,40,
+	25,254,3,202,7,10,254,5,202,21,10,33,
+	49,13,54,0,33,47,13,229,205,207,6,195,
+	118,10,58,141,15,183,32,72,33,51,13,126,
+	50,149,10,205,86,7,33,50,13,126,230,127,
+	183,32,40,58,142,15,230,127,50,142,15,183,
+	32,5,198,1,50,142,15,33,50,13,126,111,
+	23,159,103,203,125,58,142,15,40,5,198,128,
+	50,142,15,33,50,13,119,33,50,13,126,111,
+	23,159,103,229,205,237,5,193,33,211,10,54,
+	2,33,2,0,34,209,10,58,154,10,33,212,
+	10,119,58,148,10,33,213,10,119,33,209,10,
+	229,205,147,6,193,24,128,42,47,13,229,33,
+	50,13,229,205,191,4,193,24,239,33,211,10,
+	54,6,33,3,0,34,209,10,58,154,10,33,
+	212,10,119,58,148,10,33,213,10,119,33,214,
+	10,54,5,33,209,10,229,205,147,6,24,200,
+	205,106,10,33,49,13,54,0,33,47,13,229,
+	205,207,6,33,209,10,227,205,147,6,193,205,
+	80,9,205,145,8,24,248,124,170,250,99,10,
+	237,82,201,124,230,128,237,82,60,201,225,253,
+	229,221,229,221,33,0,0,221,57,233,221,249,
+	221,225,253,225,201,233,225,253,229,221,229,221,
+	33,0,0,221,57,94,35,86,35,235,57,249,
+	235,233,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
+	} ;
+
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c
--- v2.3.49/linux/drivers/net/appletalk/ipddp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/ipddp.c	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,358 @@
+/*
+ *	ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
+ *		 Appletalk-IP to IP Decapsulation driver for Linux
+ *
+ *	Authors:
+ *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *	- DDP-IP Decap by: Jay Schulist <jschlst@turbolinux.com>
+ *
+ *	Derived from:
+ *	- Almost all code already existed in net/appletalk/ddp.c I just
+ *	  moved/reorginized it into a driver file. Original IP-over-DDP code
+ *	  was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *      - skeleton.c: A network driver outline for linux.
+ *        Written 1993-94 by Donald Becker.
+ *	- dummy.c: A dummy net driver. By Nick Holloway.
+ *	- MacGate: A user space Daemon for Appletalk-IP Decap for
+ *	  Linux by Jay Schulist <jschlst@turbolinux.com>
+ *
+ *      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.
+ */
+
+static const char *version = 
+	"ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/atalk.h>
+#include <linux/ip.h>
+#include <net/route.h>
+#include <linux/inet.h>
+
+#include "ipddp.h"		/* Our stuff */
+
+static struct ipddp_route *ipddp_route_list = NULL;
+
+#ifdef CONFIG_IPDDP_ENCAP
+static int ipddp_mode = IPDDP_ENCAP;
+#else
+static int ipddp_mode = IPDDP_DECAP;
+#endif
+
+/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
+#ifndef IPDDP_DEBUG
+#define IPDDP_DEBUG 1
+#endif
+static unsigned int ipddp_debug = IPDDP_DEBUG;
+
+/* Index to functions, as function prototypes. */
+static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
+static int ipddp_create(struct ipddp_route *new_rt);
+static int ipddp_delete(struct ipddp_route *rt);
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
+static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+
+static int ipddp_open(struct net_device *dev)
+{
+#ifdef MODULE
+        MOD_INC_USE_COUNT;
+#endif
+
+        return 0;
+}
+
+static int ipddp_close(struct net_device *dev)
+{
+#ifdef MODULE
+        MOD_DEC_USE_COUNT;
+#endif
+
+        return 0;
+}
+
+int ipddp_init(struct net_device *dev)
+{
+	static unsigned version_printed = 0;
+
+	if (ipddp_debug && version_printed++ == 0)
+                printk("%s", version);
+
+	/* Let the user now what mode we are in */
+	if(ipddp_mode == IPDDP_ENCAP)
+		printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
+			dev->name);
+	if(ipddp_mode == IPDDP_DECAP)
+		printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@turbolinux.com>\n", 
+			dev->name);
+
+	/* Fill in the device structure with ethernet-generic values. */
+        ether_setup(dev);
+
+	/* Initalize the device structure. */
+        dev->hard_start_xmit = ipddp_xmit;
+
+        dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+        if(!dev->priv)
+                return -ENOMEM;
+        memset(dev->priv,0,sizeof(struct enet_statistics));
+
+	dev->open 	    = ipddp_open;
+        dev->stop 	    = ipddp_close;
+        dev->get_stats      = ipddp_get_stats;
+        dev->do_ioctl       = ipddp_ioctl;
+
+        dev->type = ARPHRD_IPDDP;       	/* IP over DDP tunnel */
+        dev->mtu = 585;
+        dev->flags |= IFF_NOARP;
+
+        /*
+         *      The worst case header we will need is currently a
+         *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
+         *      We send over SNAP so that takes another 8 bytes.
+         */
+        dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
+
+        return 0;
+}
+
+/*
+ * Get the current statistics. This may be called with the card open or closed.
+ */
+static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
+{
+        return (struct net_device_stats *)dev->priv;
+}
+
+/*
+ * Transmit LLAP/ELAP frame using aarp_send_ddp.
+ */
+static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
+        struct ddpehdr *ddp;
+        struct ipddp_route *rt;
+        struct at_addr *our_addr;
+
+	/*
+         * Find appropriate route to use, based only on IP number.
+         */
+        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
+        {
+                if(rt->ip == paddr)
+                        break;
+        }
+        if(rt == NULL)
+                return 0;
+
+        our_addr = atalk_find_dev_addr(rt->dev);
+
+	if(ipddp_mode == IPDDP_DECAP)
+		/* 
+		 * Pull off the excess room that should not be there.
+		 * This is due to a hard-header problem. This is the
+		 * quick fix for now though, till it breaks.
+		 */
+		skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
+
+	/* Create the Extended DDP header */
+	ddp = (struct ddpehdr *)skb->data;
+        ddp->deh_len = skb->len;
+        ddp->deh_hops = 1;
+        ddp->deh_pad = 0;
+        ddp->deh_sum = 0;
+
+	/*
+         * For Localtalk we need aarp_send_ddp to strip the
+         * long DDP header and place a shot DDP header on it.
+         */
+        if(rt->dev->type == ARPHRD_LOCALTLK)
+        {
+                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
+                ddp->deh_snet  = 0;
+        }
+        else
+        {
+                ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
+                ddp->deh_snet  = our_addr->s_net;
+        }
+        ddp->deh_dnode = rt->at.s_node;
+        ddp->deh_snode = our_addr->s_node;
+        ddp->deh_dport = 72;
+        ddp->deh_sport = 72;
+
+        *((__u8 *)(ddp+1)) = 22;        	/* ddp type = IP */
+        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));	/* fix up length field */
+
+        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
+
+	((struct net_device_stats *) dev->priv)->tx_packets++;
+        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
+
+        if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
+                dev_kfree_skb(skb);
+
+        return 0;
+}
+
+/*
+ * Create a routing entry. We first verify that the
+ * record does not already exist. If it does we return -EEXIST
+ */
+static int ipddp_create(struct ipddp_route *new_rt)
+{
+        struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
+	struct ipddp_route *test;
+
+        if(rt == NULL)
+                return -ENOMEM;
+
+        rt->ip = new_rt->ip;
+        rt->at = new_rt->at;
+        rt->next = NULL;
+        rt->dev = atrtr_get_dev(&rt->at);
+        if(rt->dev == NULL)
+                return (-ENETUNREACH);
+
+	test = ipddp_find_route(rt);
+	if(test != NULL)
+		return (-EEXIST);
+	
+        rt->next = ipddp_route_list;
+        ipddp_route_list = rt;
+
+        return 0;
+}
+
+/*
+ * Delete a route, we only delete a FULL match.
+ * If route does not exist we return -ENOENT.
+ */
+static int ipddp_delete(struct ipddp_route *rt)
+{
+        struct ipddp_route **r = &ipddp_route_list;
+        struct ipddp_route *tmp;
+
+        while((tmp = *r) != NULL)
+        {
+                if(tmp->ip == rt->ip
+                        && tmp->at.s_net == rt->at.s_net
+                        && tmp->at.s_node == rt->at.s_node)
+                {
+                        *r = tmp->next;
+                        kfree_s(tmp, sizeof(struct ipddp_route));
+                        return 0;
+                }
+                r = &tmp->next;
+        }
+
+        return (-ENOENT);
+}
+
+/*
+ * Find a routing entry, we only return a FULL match
+ */
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
+{
+        struct ipddp_route *f;
+
+        for(f = ipddp_route_list; f != NULL; f = f->next)
+        {
+                if(f->ip == rt->ip
+                        && f->at.s_net == rt->at.s_net
+                        && f->at.s_node == rt->at.s_node)
+                        return (f);
+        }
+
+        return (NULL);
+}
+
+static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
+
+        if(!capable(CAP_NET_ADMIN))
+                return -EPERM;
+
+        switch(cmd)
+        {
+		case SIOCADDIPDDPRT:
+                        return (ipddp_create(rt));
+
+                case SIOCFINDIPDDPRT:
+                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
+                                return -EFAULT;
+                        return 0;
+
+                case SIOCDELIPDDPRT:
+                        return (ipddp_delete(rt));
+
+                default:
+                        return -EINVAL;
+        }
+}
+
+#ifdef MODULE	/* Module specific functions for ipddp.c */
+
+static struct net_device dev_ipddp=
+{
+        "ipddp0\0   ",
+                0, 0, 0, 0,
+                0x0, 0,
+                0, 0, 0, NULL, ipddp_init
+};
+
+MODULE_PARM(ipddp_mode, "i");
+
+int init_module(void)
+{
+	int err;
+
+	err=dev_alloc_name(&dev_ipddp, "ipddp%d");
+        if(err < 0)
+                return err;
+
+	if(register_netdev(&dev_ipddp) != 0)
+                return -EIO;
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev(&dev_ipddp);
+        kfree(dev_ipddp.priv);
+	dev_ipddp.priv = NULL;
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ipddp.h linux/drivers/net/appletalk/ipddp.h
--- v2.3.49/linux/drivers/net/appletalk/ipddp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/ipddp.h	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,27 @@
+/*
+ *	ipddp.h: Header for IP-over-DDP driver for Linux.
+ */
+
+#ifndef __LINUX_IPDDP_H
+#define __LINUX_IPDDP_H
+
+#ifdef __KERNEL__
+
+#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
+#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
+#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
+
+struct ipddp_route
+{
+        struct net_device *dev;             /* Carrier device */
+        __u32 ip;                       /* IP address */
+        struct at_addr at;              /* Gateway appletalk address */
+        int flags;
+        struct ipddp_route *next;
+};
+
+#define IPDDP_ENCAP	1
+#define IPDDP_DECAP	2
+
+#endif	/* __KERNEL__ */
+#endif	/* __LINUX_IPDDP_H */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c
--- v2.3.49/linux/drivers/net/appletalk/ltpc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/ltpc.c	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,1367 @@
+/***    ltpc.c -- a driver for the LocalTalk PC card.
+ *
+ *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *
+ *      This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *      This is ALPHA code at best.  It may not work for you.  It may
+ *      damage your equipment.  It may damage your relations with other
+ *      users of your network.  Use it at your own risk!
+ *
+ *      Based in part on:
+ *      skeleton.c      by Donald Becker
+ *      dummy.c         by Nick Holloway and Alan Cox
+ *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
+ *      the netatalk source code (UMICH)
+ *      lots of work on the card...
+ *
+ *      I do not have access to the (proprietary) SDK that goes with the card.
+ *      If you do, I don't want to know about it, and you can probably write
+ *      a better driver yourself anyway.  This does mean that the pieces that
+ *      talk to the card are guesswork on my part, so use at your own risk!
+ *
+ *      This is my first try at writing Linux networking code, and is also
+ *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
+ *      welcome suggestions)
+ *
+ *      This is a loadable kernel module which seems to work at my site
+ *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
+ *      the kernel support from 1.3.3b2 including patches routing.patch
+ *      and ddp.disappears.from.chooser.  In order to run it, you will need
+ *      to patch ddp.c and aarp.c in the kernel, but only a little...
+ *
+ *      I'm fairly confident that while this is arguably badly written, the
+ *      problems that people experience will be "higher level", that is, with
+ *      complications in the netatalk code.  The driver itself doesn't do
+ *      anything terribly complicated -- it pretends to be an ether device
+ *      as far as netatalk is concerned, strips the DDP data out of the ether
+ *      frame and builds a LLAP packet to send out the card.  In the other
+ *      direction, it receives LLAP frames from the card and builds a fake
+ *      ether packet that it then tosses up to the networking code.  You can
+ *      argue (correctly) that this is an ugly way to do things, but it
+ *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
+ *
+ *      The card will do a lot more than is used here -- I *think* it has the
+ *      layers up through ATP.  Even if you knew how that part works (which I
+ *      don't) it would be a big job to carve up the kernel ddp code to insert
+ *      things at a higher level, and probably a bad idea...
+ *
+ *      There are a number of other cards that do LocalTalk on the PC.  If
+ *      nobody finds any insurmountable (at the netatalk level) problems
+ *      here, this driver should encourage people to put some work into the
+ *      other cards (some of which I gather are still commercially available)
+ *      and also to put hooks for LocalTalk into the official ddp code.
+ *
+ *      I welcome comments and suggestions.  This is my first try at Linux
+ *      networking stuff, and there are probably lots of things that I did
+ *      suboptimally.  
+ *
+ ***/
+
+/***
+ *
+ * $Log: ltpc.c,v $
+ * Revision 1.1.2.1  2000/03/01 05:35:07  jgarzik
+ * at and tr cleanup
+ *
+ * Revision 1.8  1997/01/28 05:44:54  bradford
+ * Clean up for non-module a little.
+ * Hacked about a bit to clean things up - Alan Cox 
+ * Probably broken it from the origina 1.8
+ *
+
+ * 1998/11/09: David Huggins-Daines <dhd@debian.org>
+ * Cleaned up the initialization code to use the standard autoirq methods,
+   and to probe for things in the standard order of i/o, irq, dma.  This
+   removes the "reset the reset" hack, because I couldn't figure out an
+   easy way to get the card to trigger an interrupt after it.
+ * Added support for passing configuration parameters on the kernel command
+   line and through insmod
+ * Changed the device name from "ltalk0" to "lt0", both to conform with the
+   other localtalk driver, and to clear up the inconsistency between the
+   module and the non-module versions of the driver :-)
+ * Added a bunch of comments (I was going to make some enums for the state
+   codes and the register offsets, but I'm still not sure exactly what their
+   semantics are)
+ * Don't poll anymore in interrupt-driven mode
+ * It seems to work as a module now (as of 2.1.127), but I don't think
+   I'm responsible for that...
+
+ *
+ * Revision 1.7  1996/12/12 03:42:33  bradford
+ * DMA alloc cribbed from 3c505.c.
+ *
+ * Revision 1.6  1996/12/12 03:18:58  bradford
+ * Added virt_to_bus; works in 2.1.13.
+ *
+ * Revision 1.5  1996/12/12 03:13:22  root
+ * xmitQel initialization -- think through better though.
+ *
+ * Revision 1.4  1996/06/18 14:55:55  root
+ * Change names to ltpc. Tabs. Took a shot at dma alloc,
+ * although more needs to be done eventually.
+ *
+ * Revision 1.3  1996/05/22 14:59:39  root
+ * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
+ *
+ * Revision 1.2  1996/05/22 14:58:24  root
+ * Change tabs mostly.
+ *
+ * Revision 1.1  1996/04/23 04:45:09  root
+ * Initial revision
+ *
+ * Revision 0.16  1996/03/05 15:59:56  root
+ * Change ARPHRD_LOCALTLK definition to the "real" one.
+ *
+ * Revision 0.15  1996/03/05 06:28:30  root
+ * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
+ * it's getting closer.
+ *
+ * Revision 0.14  1996/02/25 17:38:32  root
+ * More cleanups.  Removed query to card on get_stats.
+ *
+ * Revision 0.13  1996/02/21  16:27:40  root
+ * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
+ * Clean up receive code a little.
+ *
+ * Revision 0.12  1996/02/19  16:34:53  root
+ * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
+ * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
+ * including packet printing, 4 for lower level (card i/o) stuff.
+ *
+ * Revision 0.11  1996/02/12  15:53:38  root
+ * Added router sends (requires new aarp.c patch)
+ *
+ * Revision 0.10  1996/02/11  00:19:35  root
+ * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
+ *
+ * Revision 0.9  1996/02/10  23:59:35  root
+ * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
+ * has a *different* definition of struct sockaddr_at than the Linux kernel
+ * does.  This is an "insidious and invidious" bug...
+ * (Actually the preceding comment is false -- it's the atalk.h in the
+ * ancient atalk-0.06 that's the problem)
+ *
+ * Revision 0.8  1996/02/10 19:09:00  root
+ * Merge 1.3 changes.  Tested OK under 1.3.60.
+ *
+ * Revision 0.7  1996/02/10 17:56:56  root
+ * Added debug=1 parameter on insmod for debugging prints.  Tried
+ * to fix timer unload on rmmod, but I don't think that's the problem.
+ *
+ * Revision 0.6  1995/12/31  19:01:09  root
+ * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
+ * Clean up initial probing -- sometimes the card wakes up latched in reset.
+ *
+ * Revision 0.5  1995/12/22  06:03:44  root
+ * Added comments in front and cleaned up a bit.
+ * This version sent out to people.
+ *
+ * Revision 0.4  1995/12/18  03:46:44  root
+ * Return shortDDP to longDDP fake to 0/0.  Added command structs.
+ *
+ ***/
+
+/* ltpc jumpers are:
+*
+*	Interrupts -- set at most one.  If none are set, the driver uses
+*	polled mode.  Because the card was developed in the XT era, the
+*	original documentation refers to IRQ2.  Since you'll be running
+*	this on an AT (or later) class machine, that really means IRQ9.
+*
+*	SW1	IRQ 4
+*	SW2	IRQ 3
+*	SW3	IRQ 9 (2 in original card documentation only applies to XT)
+*
+*
+*	DMA -- choose DMA 1 or 3, and set both corresponding switches.
+*
+*	SW4	DMA 3
+*	SW5	DMA 1
+*	SW6	DMA 3
+*	SW7	DMA 1
+*
+*
+*	I/O address -- choose one.  
+*
+*	SW8	220 / 240
+*/
+
+/*	To have some stuff logged, do 
+*	insmod ltpc.o debug=1
+*
+*	For a whole bunch of stuff, use higher numbers.
+*
+*	The default is 0, i.e. no messages except for the probe results.
+*/
+
+/* insmod-tweakable variables */
+static int debug=0;
+#define DEBUG_VERBOSE 1
+#define DEBUG_UPPER 2
+#define DEBUG_LOWER 4
+
+static int io=0;
+static int irq=0;
+static int dma=0;
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include <linux/atalk.h>
+
+/* our stuff */
+#include "ltpc.h"
+
+/* function prototypes */
+static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
+	void *dbuf, int dbuflen);
+static int sendup_buffer (struct net_device *dev);
+
+/* Dma Memory related stuff, cribbed directly from 3c505.c */
+
+static unsigned long dma_mem_alloc(int size)
+{
+        int order = get_order(size);
+
+        return __get_dma_pages(GFP_KERNEL, order);
+}
+
+/* DMA data buffer, DMA command buffer */
+static unsigned char *ltdmabuf;
+static unsigned char *ltdmacbuf;
+
+/* private struct, holds our appletalk address */
+
+struct ltpc_private
+{
+	struct net_device_stats stats;
+	struct at_addr my_addr;
+};
+
+/* transmit queue element struct */
+
+struct xmitQel {
+	struct xmitQel *next;
+	/* command buffer */
+	unsigned char *cbuf;
+	short cbuflen;
+	/* data buffer */
+	unsigned char *dbuf;
+	short dbuflen;
+	unsigned char QWrite;	/* read or write data */
+	unsigned char mailbox;
+};
+
+/* the transmit queue itself */
+
+static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
+
+static void enQ(struct xmitQel *qel)
+{
+	unsigned long flags;
+	qel->next = NULL;
+	save_flags(flags);
+	cli();
+	if (xmQtl) {
+		xmQtl->next = qel;
+	} else {
+		xmQhd = qel;
+	}
+	xmQtl = qel;
+	restore_flags(flags);
+
+	if (debug&DEBUG_LOWER)
+		printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
+}
+
+static struct xmitQel *deQ(void)
+{
+	unsigned long flags;
+	int i;
+	struct xmitQel *qel=NULL;
+	save_flags(flags);
+	cli();
+	if (xmQhd) {
+		qel = xmQhd;
+		xmQhd = qel->next;
+		if(!xmQhd) xmQtl = NULL;
+	}
+	restore_flags(flags);
+
+	if ((debug&DEBUG_LOWER) && qel) {
+		int n;
+		printk("ltpc: dequeued command ");
+		n = qel->cbuflen;
+		if (n>100) n=100;
+		for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
+		printk("\n");
+	}
+
+	return qel;
+}
+
+/* and... the queue elements we'll be using */
+static struct xmitQel qels[16];
+
+/* and their corresponding mailboxes */
+static unsigned char mailbox[16];
+static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static int wait_timeout(struct net_device *dev, int c)
+{
+	/* returns true if it stayed c */
+	/* this uses base+6, but it's ok */
+	int i;
+	int timeout;
+
+	/* twenty second or so total */
+
+	for(i=0;i<20000;i++) {
+		if ( c != inb_p(dev->base_addr+6) ) return 0;
+		for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
+	}
+	return 1; /* timed out */
+}
+
+/* get the first free mailbox */
+
+static int getmbox(void)
+{
+	unsigned long flags;
+	int i;
+
+	save_flags(flags);
+	cli();
+	for(i=1;i<16;i++) if(!mboxinuse[i]) {
+		mboxinuse[i]=1;
+		restore_flags(flags);
+		return i;
+	}
+	restore_flags(flags);
+	return 0;
+}
+
+/* read a command from the card */
+static void handlefc(struct net_device *dev)
+{
+	/* called *only* from idle, non-reentrant */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+	unsigned long flags;
+
+
+	flags=claim_dma_lock();
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+	set_dma_count(dma,50);
+	enable_dma(dma);
+	release_dma_lock(flags);
+
+	inb_p(base+3);
+	inb_p(base+2);
+
+	if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
+}
+
+/* read data from the card */
+static void handlefd(struct net_device *dev)
+{
+	int dma = dev->dma;
+	int base = dev->base_addr;
+	unsigned long flags;
+
+	flags=claim_dma_lock();
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,800);
+	enable_dma(dma);
+	release_dma_lock(flags);
+
+	inb_p(base+3);
+	inb_p(base+2);
+
+	if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
+	sendup_buffer(dev);
+} 
+
+static void handlewrite(struct net_device *dev)
+{
+	/* called *only* from idle, non-reentrant */
+	/* on entry, 0xfb and ltdmabuf holds data */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+	unsigned long flags;
+	
+	flags=claim_dma_lock();
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_WRITE);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,800);
+	enable_dma(dma);
+	release_dma_lock(flags);
+	
+	inb_p(base+3);
+	inb_p(base+2);
+
+	if ( wait_timeout(dev,0xfb) ) {
+		flags=claim_dma_lock();
+		printk("timed out in handlewrite, dma res %d\n",
+			get_dma_residue(dev->dma) );
+		release_dma_lock(flags);
+	}
+}
+
+static void handleread(struct net_device *dev)
+{
+	/* on entry, 0xfb */
+	/* on exit, ltdmabuf holds data */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+	unsigned long flags;
+
+	
+	flags=claim_dma_lock();
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,800);
+	enable_dma(dma);
+	release_dma_lock(flags);
+
+	inb_p(base+3);
+	inb_p(base+2);
+	if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
+}
+
+static void handlecommand(struct net_device *dev)
+{
+	/* on entry, 0xfa and ltdmacbuf holds command */
+	int dma = dev->dma;
+	int base = dev->base_addr;
+	unsigned long flags;
+
+	flags=claim_dma_lock();
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_WRITE);
+	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
+	set_dma_count(dma,50);
+	enable_dma(dma);
+	release_dma_lock(flags);
+	inb_p(base+3);
+	inb_p(base+2);
+	if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
+} 
+
+/* ready made command for getting the result from the card */
+static unsigned char rescbuf[2] = {LT_GETRESULT,0};
+static unsigned char resdbuf[2];
+
+static int QInIdle=0;
+
+/* idle expects to be called with the IRQ line high -- either because of
+ * an interrupt, or because the line is tri-stated
+ */
+
+static void idle(struct net_device *dev)
+{
+	unsigned long flags;
+	int state;
+	/* FIXME This is initialized to shut the warning up, but I need to
+	 * think this through again.
+	 */
+	struct xmitQel *q=0;
+	int oops;
+	int i;
+	int base = dev->base_addr;
+
+	save_flags(flags);
+	cli();
+	if(QInIdle) {
+		restore_flags(flags);
+		return;
+	}
+	QInIdle = 1;
+
+
+	restore_flags(flags);
+
+	/* this tri-states the IRQ line */
+	(void) inb_p(base+6);
+
+	oops = 100;
+
+loop:
+	if (0>oops--) { 
+		printk("idle: looped too many times\n");
+		goto done;
+	}
+
+	state = inb_p(base+6);
+	if (state != inb_p(base+6)) goto loop;
+
+	switch(state) {
+		case 0xfc:
+			/* incoming command */
+			if (debug&DEBUG_LOWER) printk("idle: fc\n");
+			handlefc(dev); 
+			break;
+		case 0xfd:
+			/* incoming data */
+			if(debug&DEBUG_LOWER) printk("idle: fd\n");
+			handlefd(dev); 
+			break;
+		case 0xf9:
+			/* result ready */
+			if (debug&DEBUG_LOWER) printk("idle: f9\n");
+			if(!mboxinuse[0]) {
+				mboxinuse[0] = 1;
+				qels[0].cbuf = rescbuf;
+				qels[0].cbuflen = 2;
+				qels[0].dbuf = resdbuf;
+				qels[0].dbuflen = 2;
+				qels[0].QWrite = 0;
+				qels[0].mailbox = 0;
+				enQ(&qels[0]);
+			}
+			inb_p(dev->base_addr+1);
+			inb_p(dev->base_addr+0);
+			if( wait_timeout(dev,0xf9) )
+				printk("timed out idle f9\n");
+			break;
+		case 0xf8:
+			/* ?? */
+			if (xmQhd) {
+				inb_p(dev->base_addr+1);
+				inb_p(dev->base_addr+0);
+				if(wait_timeout(dev,0xf8) )
+					printk("timed out idle f8\n");
+			} else {
+				goto done;
+			}
+			break;
+		case 0xfa:
+			/* waiting for command */
+			if(debug&DEBUG_LOWER) printk("idle: fa\n");
+			if (xmQhd) {
+				q=deQ();
+				memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
+				ltdmacbuf[1] = q->mailbox;
+				if (debug>1) { 
+					int n;
+					printk("ltpc: sent command     ");
+					n = q->cbuflen;
+					if (n>100) n=100;
+					for(i=0;i<n;i++)
+						printk("%02x ",ltdmacbuf[i]);
+					printk("\n");
+				}
+				handlecommand(dev);
+					if(0xfa==inb_p(base+6)) {
+						/* we timed out, so return */
+						goto done;
+					} 
+			} else {
+				/* we don't seem to have a command */
+				if (!mboxinuse[0]) {
+					mboxinuse[0] = 1;
+					qels[0].cbuf = rescbuf;
+					qels[0].cbuflen = 2;
+					qels[0].dbuf = resdbuf;
+					qels[0].dbuflen = 2;
+					qels[0].QWrite = 0;
+					qels[0].mailbox = 0;
+					enQ(&qels[0]);
+				} else {
+					printk("trouble: response command already queued\n");
+					goto done;
+				}
+			} 
+			break;
+		case 0Xfb:
+			/* data transfer ready */
+			if(debug&DEBUG_LOWER) printk("idle: fb\n");
+			if(q->QWrite) {
+				memcpy(ltdmabuf,q->dbuf,q->dbuflen);
+				handlewrite(dev);
+			} else {
+				handleread(dev);
+				/* non-zero mailbox numbers are for
+				   commmands, 0 is for GETRESULT
+				   requests */
+				if(q->mailbox) {
+					memcpy(q->dbuf,ltdmabuf,q->dbuflen);
+				} else { 
+					/* this was a result */
+					mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
+					mboxinuse[0]=0;
+				}
+			}
+			break;
+	}
+	goto loop;
+
+done:
+	QInIdle=0;
+
+	/* now set the interrupts back as appropriate */
+	/* the first read takes it out of tri-state (but still high) */
+	/* the second resets it */
+	/* note that after this point, any read of base+6 will
+	   trigger an interrupt */
+
+	if (dev->irq) {
+		inb_p(base+7);
+		inb_p(base+7);
+	}
+	return;
+}
+
+
+static int do_write(struct net_device *dev, void *cbuf, int cbuflen,
+	void *dbuf, int dbuflen)
+{
+
+	int i = getmbox();
+	int ret;
+
+	if(i) {
+		qels[i].cbuf = (unsigned char *) cbuf;
+		qels[i].cbuflen = cbuflen;
+		qels[i].dbuf = (unsigned char *) dbuf;
+		qels[i].dbuflen = dbuflen;
+		qels[i].QWrite = 1;
+		qels[i].mailbox = i;  /* this should be initted rather */
+		enQ(&qels[i]);
+		idle(dev);
+		ret = mailbox[i];
+		mboxinuse[i]=0;
+		return ret;
+	}
+	printk("ltpc: could not allocate mbox\n");
+	return -1;
+}
+
+static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
+	void *dbuf, int dbuflen)
+{
+
+	int i = getmbox();
+	int ret;
+
+	if(i) {
+		qels[i].cbuf = (unsigned char *) cbuf;
+		qels[i].cbuflen = cbuflen;
+		qels[i].dbuf = (unsigned char *) dbuf;
+		qels[i].dbuflen = dbuflen;
+		qels[i].QWrite = 0;
+		qels[i].mailbox = i;  /* this should be initted rather */
+		enQ(&qels[i]);
+		idle(dev);
+		ret = mailbox[i];
+		mboxinuse[i]=0;
+		return ret;
+	}
+	printk("ltpc: could not allocate mbox\n");
+	return -1;
+}
+
+/* end of idle handlers -- what should be seen is do_read, do_write */
+
+static struct timer_list ltpc_timer;
+
+static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *ltpc_get_stats(struct net_device *dev);
+
+static int ltpc_open(struct net_device *dev)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static int ltpc_close(struct net_device *dev)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static int read_30 ( struct net_device *dev)
+{
+	lt_command c;
+	c.getflags.command = LT_GETFLAGS;
+	return do_read(dev, &c, sizeof(c.getflags),&c,0);
+}
+
+static int set_30 (struct net_device *dev,int x)
+{
+	lt_command c;
+	c.setflags.command = LT_SETFLAGS;
+	c.setflags.flags = x;
+	return do_write(dev, &c, sizeof(c.setflags),&c,0);
+}
+
+/* LLAP to DDP translation */
+
+static int sendup_buffer (struct net_device *dev)
+{
+	/* on entry, command is in ltdmacbuf, data in ltdmabuf */
+	/* called from idle, non-reentrant */
+
+	int dnode, snode, llaptype, len; 
+	int sklen;
+	struct sk_buff *skb;
+	struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
+	struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
+
+	if (ltc->command != LT_RCVLAP) {
+		printk("unknown command 0x%02x from ltpc card\n",ltc->command);
+		return(-1);
+	}
+	dnode = ltc->dnode;
+	snode = ltc->snode;
+	llaptype = ltc->laptype;
+	len = ltc->length; 
+
+	sklen = len;
+	if (llaptype == 1) 
+		sklen += 8;  /* correct for short ddp */
+	if(sklen > 800) {
+		printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
+			dev->name,sklen);
+		return -1;
+	}
+
+	if ( (llaptype==0) || (llaptype>2) ) {
+		printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
+		return -1;
+	}
+
+
+	skb = dev_alloc_skb(3+sklen);
+	if (skb == NULL) 
+	{
+		printk("%s: dropping packet due to memory squeeze.\n",
+			dev->name);
+		return -1;
+	}
+	skb->dev = dev;
+
+	if (sklen > len)
+		skb_reserve(skb,8);
+	skb_put(skb,len+3);
+	skb->protocol = htons(ETH_P_LOCALTALK);
+	/* add LLAP header */
+	skb->data[0] = dnode;
+	skb->data[1] = snode;
+	skb->data[2] = llaptype;
+	skb->mac.raw = skb->data;	/* save pointer to llap header */
+	skb_pull(skb,3);
+
+	/* copy ddp(s,e)hdr + contents */
+	memcpy(skb->data,(void*)ltdmabuf,len);
+
+	skb->h.raw = skb->data;
+
+	stats->rx_packets++;
+	stats->rx_bytes+=skb->len;
+
+	/* toss it onwards */
+	netif_rx(skb);
+	return 0;
+}
+
+/* the handler for the board interrupt */
+ 
+static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+{
+	struct net_device *dev = dev_id;
+
+	if (dev==NULL) {
+		printk("ltpc_interrupt: unknown device.\n");
+		return;
+	}
+
+	inb_p(dev->base_addr+6);  /* disable further interrupts from board */
+
+	idle(dev); /* handle whatever is coming in */
+ 
+	/* idle re-enables interrupts from board */ 
+
+	return;
+}
+
+/***
+ *
+ *    The ioctls that the driver responds to are:
+ *
+ *    SIOCSIFADDR -- do probe using the passed node hint.
+ *    SIOCGIFADDR -- return net, node.
+ *
+ *    some of this stuff should be done elsewhere.
+ *
+ ***/
+
+static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
+	/* we'll keep the localtalk node address in dev->pa_addr */
+	struct at_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr;
+	struct lt_init c;
+	int ltflags;
+
+	if(debug&DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
+
+	switch(cmd) {
+		case SIOCSIFADDR:
+
+			aa->s_net  = sa->sat_addr.s_net;
+      
+			/* this does the probe and returns the node addr */
+			c.command = LT_INIT;
+			c.hint = sa->sat_addr.s_node;
+
+			aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
+
+			/* get all llap frames raw */
+			ltflags = read_30(dev);
+			ltflags |= LT_FLAG_ALLLAP;
+			set_30 (dev,ltflags);  
+
+			dev->broadcast[0] = 0xFF;
+			dev->dev_addr[0] = aa->s_node;
+
+			dev->addr_len=1;
+   
+			return 0;
+
+		case SIOCGIFADDR:
+
+			sa->sat_addr.s_net = aa->s_net;
+			sa->sat_addr.s_node = aa->s_node;
+
+			return 0;
+
+		default: 
+			return -EINVAL;
+	}
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+	/* This needs to be present to keep netatalk happy. */
+	/* Actually netatalk needs fixing! */
+}
+
+static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, 
+	unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+	if(debug&DEBUG_VERBOSE)
+		printk("ltpc_hard_header called for device %s\n",
+			dev->name);
+	return 0;
+}
+
+static int ltpc_init(struct net_device *dev)
+{
+	/* Initialize the device structure. */
+  
+	/* Fill in the fields of the device structure with ethernet-generic values. */
+	ltalk_setup(dev);
+	dev->hard_start_xmit = ltpc_xmit;
+	dev->hard_header = ltpc_hard_header;
+
+	dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL);
+	if(!dev->priv)
+	{
+		printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name);
+		return -ENOMEM;
+	}
+
+	memset(dev->priv, 0, sizeof(struct ltpc_private));
+	dev->get_stats = ltpc_get_stats;
+
+	dev->open = ltpc_open;
+	dev->stop = ltpc_close;
+
+	/* add the ltpc-specific things */
+	dev->do_ioctl = &ltpc_ioctl;
+
+	dev->set_multicast_list = &set_multicast_list;
+	dev->mc_list = NULL;
+
+	return 0;
+}
+
+static int ltpc_poll_counter = 0;
+
+static void ltpc_poll(unsigned long l)
+{
+	struct net_device *dev = (struct net_device *) l;
+
+	del_timer(&ltpc_timer);
+
+	if(debug&DEBUG_VERBOSE) {
+		if (!ltpc_poll_counter) {
+			ltpc_poll_counter = 50;
+			printk("ltpc poll is alive\n");
+		}
+		ltpc_poll_counter--;
+	}
+  
+	if (!dev)
+		return;  /* we've been downed */
+
+	idle(dev);
+	ltpc_timer.expires = jiffies+5;
+	
+	add_timer(&ltpc_timer);
+}
+
+/* DDP to LLAP translation */
+
+static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	/* in kernel 1.3.xx, on entry skb->data points to ddp header,
+	 * and skb->len is the length of the ddp data + ddp header
+	 */
+
+	struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
+
+	int i;
+	struct lt_sendlap cbuf;
+
+	cbuf.command = LT_SENDLAP;
+	cbuf.dnode = skb->data[0];
+	cbuf.laptype = skb->data[2];
+	skb_pull(skb,3);	/* skip past LLAP header */
+	cbuf.length = skb->len;	/* this is host order */
+	skb->h.raw=skb->data;
+
+	if(debug&DEBUG_UPPER) {
+		printk("command ");
+		for(i=0;i<6;i++)
+			printk("%02x ",((unsigned char *)&cbuf)[i]);
+		printk("\n");
+	}
+
+	do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
+
+	if(debug&DEBUG_UPPER) {
+		printk("sent %d ddp bytes\n",skb->len);
+		for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
+		printk("\n");
+	}
+
+	stats->tx_packets++;
+	stats->tx_bytes+=skb->len;
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static struct net_device_stats *ltpc_get_stats(struct net_device *dev)
+{
+	struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats;
+	return stats;
+}
+
+/* initialization stuff */
+  
+int __init ltpc_probe_dma(int base)
+{
+	int dma = 0;
+  	int timeout;
+  	unsigned long f;
+  
+  	if (!request_dma(1,"ltpc")) {
+  		f=claim_dma_lock();
+  		disable_dma(1);
+  		clear_dma_ff(1);
+		set_dma_mode(1,DMA_MODE_WRITE);
+		set_dma_addr(1,virt_to_bus(ltdmabuf));
+		set_dma_count(1,sizeof(struct lt_mem));
+		enable_dma(1);
+		release_dma_lock(f);
+		dma|=1;
+	}
+	if (!request_dma(3,"ltpc")) {
+		f=claim_dma_lock();
+		disable_dma(3);
+		clear_dma_ff(3);
+		set_dma_mode(3,DMA_MODE_WRITE);
+		set_dma_addr(3,virt_to_bus(ltdmabuf));
+		set_dma_count(3,sizeof(struct lt_mem));
+		enable_dma(3);
+		release_dma_lock(f);
+		dma|=2;
+	}
+
+	/* set up request */
+
+	/* FIXME -- do timings better! */
+
+	ltdmabuf[0] = LT_READMEM;
+	ltdmabuf[1] = 1;  /* mailbox */
+	ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
+	ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
+	ltdmabuf[6] = 0; /* dunno if this is necessary */
+
+	inb_p(io+1);
+	inb_p(io+0);
+	timeout = jiffies+100*HZ/100;
+	while(time_before(jiffies, timeout)) {
+		if ( 0xfa == inb_p(io+6) ) break;
+	}
+
+	inb_p(io+3);
+	inb_p(io+2);
+	while(time_before(jiffies, timeout)) {
+		if ( 0xfb == inb_p(io+6) ) break;
+	}
+
+	/* release the other dma channel (if we opened both of them) */
+
+	if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
+		dma&=1;
+		free_dma(3);
+	}
+  
+	if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){
+		dma&=0x2;
+		free_dma(1);
+	}
+
+	/* fix up dma number */
+	dma|=1;
+
+	return dma;
+}
+
+int __init ltpc_probe(struct net_device *dev)
+{
+	int err;
+	int x=0,y=0;
+	int timeout;
+	int autoirq;
+	unsigned long flags;
+	unsigned long f;
+
+	save_flags(flags);
+
+	/* probe for the I/O port address */
+	if (io != 0x240 && !check_region(0x220,8)) {
+		x = inb_p(0x220+6);
+		if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
+	}
+	
+	if (io != 0x220 && !check_region(0x240,8)) {
+		y = inb_p(0x240+6);
+		if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
+	} 
+
+	if(io) {
+		/* found it, now grab it */
+		request_region(io,8,"ltpc");
+	} else {
+		/* give up in despair */
+		printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
+			x,y);
+		restore_flags(flags);
+		return -1;
+	}
+
+	/* probe for the IRQ line */
+	if (irq < 2) {
+		autoirq_setup(2);
+
+		/* reset the interrupt line */
+		inb_p(io+7);
+		inb_p(io+7);
+		/* trigger an interrupt (I hope) */
+		inb_p(io+6);
+
+		autoirq = autoirq_report(1);
+
+		if (autoirq == 0) {
+			printk("ltpc: probe at %#x failed to detect IRQ line.\n",
+				io);
+		}
+		else {
+			irq = autoirq;
+		}
+	}
+
+	/* allocate a DMA buffer */
+	ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
+
+	if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
+
+	if (!ltdmabuf) {
+		printk("ltpc: mem alloc failed\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	if(debug&DEBUG_VERBOSE) {
+		printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
+	}
+
+	/* reset the card */
+
+	inb_p(io+1);
+	inb_p(io+3);
+	timeout = jiffies+2*HZ/100;
+	while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */
+	inb_p(io+0);
+	inb_p(io+2);
+	inb_p(io+7); /* clear reset */
+	inb_p(io+4); 
+	inb_p(io+5);
+	inb_p(io+5); /* enable dma */
+	inb_p(io+6); /* tri-state interrupt line */
+
+	timeout = jiffies+100*HZ/100;
+	
+	while(time_before(jiffies, timeout)) {
+		/* wait for the card to complete initialization */
+	}
+ 
+	/* now, figure out which dma channel we're using, unless it's
+	   already been specified */
+	/* well, 0 is a legal DMA channel, but the LTPC card doesn't
+	   use it... */
+	if (dma == 0) {
+		dma = ltpc_probe_dma(io);
+		if (!dma) {  /* no dma channel */
+			printk("No DMA channel found on ltpc card.\n");
+			restore_flags(flags);
+			return -1;
+		}
+	}
+
+	/* print out friendly message */
+
+	if(irq)
+		printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
+	else
+		printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
+
+	/* seems more logical to do this *after* probing the card... */
+	err = ltpc_init(dev);
+	if (err) return err;
+
+	dev->base_addr = io;
+	dev->irq = irq;
+	dev->dma = dma;
+
+	/* the card will want to send a result at this point */
+	/* (I think... leaving out this part makes the kernel crash,
+           so I put it back in...) */
+
+	f=claim_dma_lock();
+	disable_dma(dma);
+	clear_dma_ff(dma);
+	set_dma_mode(dma,DMA_MODE_READ);
+	set_dma_addr(dma,virt_to_bus(ltdmabuf));
+	set_dma_count(dma,0x100);
+	enable_dma(dma);
+	release_dma_lock(f);
+
+	(void) inb_p(io+3);
+	(void) inb_p(io+2);
+	timeout = jiffies+100*HZ/100;
+	while(time_before(jiffies, timeout)) {
+		if( 0xf9 == inb_p(io+6)) break;
+	}
+
+	if(debug&DEBUG_VERBOSE) {
+		printk("setting up timer and irq\n");
+	}
+
+	if (irq) {
+		/* grab it and don't let go :-) */
+		(void) request_irq( irq, &ltpc_interrupt, 0, "ltpc", dev);
+		(void) inb_p(io+7);  /* enable interrupts from board */
+		(void) inb_p(io+7);  /* and reset irq line */
+	} else {
+		/* polled mode -- 20 times per second */
+		/* this is really, really slow... should it poll more often? */
+		init_timer(&ltpc_timer);
+		ltpc_timer.function=ltpc_poll;
+		ltpc_timer.data = (unsigned long) dev;
+
+		ltpc_timer.expires = jiffies + 5;
+		add_timer(&ltpc_timer);
+		restore_flags(flags); 
+	}
+
+	return 0;
+}
+
+/* handles "ltpc=io,irq,dma" kernel command lines */
+static int __init ltpc_setup(char *str)
+{
+	int ints[5];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] == 0) {
+		if (str && !strncmp(str, "auto", 4)) {
+			/* do nothing :-) */
+		}
+		else {
+			/* usage message */
+			printk (KERN_ERR
+				"ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+		}
+		return 1;
+	} else {
+		io = ints[1];
+		if (ints[0] > 1) {
+			irq = ints[2];
+			return 1;
+		}
+		if (ints[0] > 2) {
+			dma = ints[3];
+			return 1;
+		}
+		/* ignore any other paramters */
+	}
+	return 1;
+}
+
+__setup("ltpc=", ltpc_setup);
+
+#ifdef MODULE
+
+static char dev_name[8];
+
+static struct net_device dev_ltpc = {
+		dev_name, 
+		0, 0, 0, 0,
+	 	0x0, 0,
+	 	0, 0, 0, NULL, ltpc_probe };
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+
+int init_module(void)
+{
+	int err, result;
+	
+        if(io == 0)
+		printk(KERN_NOTICE
+		       "ltpc: Autoprobing is not recommended for modules\n");
+
+	/* Find a name for this unit */
+	err=dev_alloc_name(&dev_ltpc,"lt%d");
+	
+	if(err<0)
+		return err;
+
+	if ((result = register_netdev(&dev_ltpc)) != 0) {
+		printk(KERN_DEBUG "could not register Localtalk-PC device\n");
+		return result;
+	} else {
+		if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
+		return 0;
+	}
+}
+
+void cleanup_module(void)
+{
+	long timeout;
+
+	ltpc_timer.data = 0;  /* signal the poll routine that we're done */
+
+	if(debug&DEBUG_VERBOSE) printk("freeing irq\n");
+
+	if(dev_ltpc.irq) {
+		free_irq(dev_ltpc.irq,&dev_ltpc);
+		dev_ltpc.irq = 0;
+	}
+
+	if(del_timer(&ltpc_timer)) 
+	{
+		/* either the poll was never started, or a poll is in process */
+		if(debug&DEBUG_VERBOSE) printk("waiting\n");
+		/* if it's in process, wait a bit for it to finish */
+		timeout = jiffies+HZ; 
+		add_timer(&ltpc_timer);
+		while(del_timer(&ltpc_timer) && time_after(timeout, jiffies))
+		{
+			add_timer(&ltpc_timer);
+			schedule();
+		}
+	}
+
+	if(debug&DEBUG_VERBOSE) printk("freeing dma\n");
+
+	if(dev_ltpc.dma) {
+		free_dma(dev_ltpc.dma);
+		dev_ltpc.dma = 0;
+	}
+
+	if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n");
+
+	if(dev_ltpc.base_addr) {
+		release_region(dev_ltpc.base_addr,8);
+		dev_ltpc.base_addr = 0;
+	}
+
+	if(debug&DEBUG_VERBOSE) printk("free_pages\n");
+
+	free_pages( (unsigned long) ltdmabuf, get_order(1000));
+	ltdmabuf=NULL;
+	ltdmacbuf=NULL;
+
+	if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n");
+
+	unregister_netdev(&dev_ltpc);
+
+	if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
+}
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ltpc.h linux/drivers/net/appletalk/ltpc.h
--- v2.3.49/linux/drivers/net/appletalk/ltpc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/appletalk/ltpc.h	Fri Mar  3 12:54:44 2000
@@ -0,0 +1,73 @@
+/***   ltpc.h
+ *
+ *
+ ***/
+
+#define LT_GETRESULT  0x00
+#define LT_WRITEMEM   0x01
+#define LT_READMEM    0x02
+#define LT_GETFLAGS   0x04
+#define LT_SETFLAGS   0x05
+#define LT_INIT       0x10
+#define LT_SENDLAP    0x13
+#define LT_RCVLAP     0x14
+
+/* the flag that we care about */
+#define LT_FLAG_ALLLAP 0x04
+
+struct lt_getresult {
+	unsigned char command;
+	unsigned char mailbox;
+};
+
+struct lt_mem {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned short addr;	/* host order */
+	unsigned short length;	/* host order */
+};
+
+struct lt_setflags {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned char flags;
+};
+
+struct lt_getflags {
+	unsigned char command;
+	unsigned char mailbox;
+};
+
+struct lt_init {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned char hint;
+};
+
+struct lt_sendlap {
+	unsigned char command;
+	unsigned char mailbox;
+	unsigned char dnode;
+	unsigned char laptype;
+	unsigned short length;	/* host order */
+};
+
+struct lt_rcvlap {
+	unsigned char command;
+	unsigned char dnode;
+	unsigned char snode;
+	unsigned char laptype;
+	unsigned short length;	/* host order */
+};
+
+union lt_command {
+	struct lt_getresult getresult;
+	struct lt_mem mem;
+	struct lt_setflags setflags;
+	struct lt_getflags getflags;
+	struct lt_init init;
+	struct lt_sendlap sendlap;
+	struct lt_rcvlap rcvlap;
+};
+typedef union lt_command lt_command;
+
diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops.c linux/drivers/net/cops.c
--- v2.3.49/linux/drivers/net/cops.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/cops.c	Wed Dec 31 16:00:00 1969
@@ -1,1066 +0,0 @@
-/*      cops.c: LocalTalk driver for Linux.
- *
- *	Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- *
- *	With more than a little help from;
- *	- Alan Cox <Alan.Cox@linux.org> 
- *
- *      Derived from:
- *      - skeleton.c: A network driver outline for linux.
- *        Written 1993-94 by Donald Becker.
- *	- ltpc.c: A driver for the LocalTalk PC card.
- *	  Written by Bradford W. Johnson.
- *
- *      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.
- *
- *	Changes:
- *	19970608	Alan Cox	Allowed dual card type support
- *					Can set board type in insmod
- *					Hooks for cops_setup routine
- *					(not yet implemented).
- *	19971101	Jay Schulist	Fixes for multiple lt* devices.
- *	19980607	Steven Hirsch	Fixed the badly broken support
- *					for Tangent type cards. Only
- *                                      tested on Daystar LT200. Some
- *                                      cleanup of formatting and program
- *                                      logic.  Added emacs 'local-vars'
- *                                      setup for Jay's brace style.
- *	20000211	Alan Cox	Cleaned up for softnet
- */
-
-static const char *version =
-"cops.c:v0.04 6/7/98 Jay Schulist <jschlst@turbolinux.com>\n";
-/*
- *  Sources:
- *      COPS Localtalk SDK. This provides almost all of the information
- *      needed.
- */
-
-/*
- * insmod/modprobe configurable stuff.
- *	- IO Port, choose one your card supports or 0 if you dare.
- *	- IRQ, also choose one your card supports or nothing and let
- *	  the driver figure it out.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>	/* For ltalk_setup() */
-#include <linux/delay.h>	/* For udelay() */
-#include <linux/atalk.h>
-
-#include "cops.h"		/* Our Stuff */
-#include "cops_ltdrv.h"		/* Firmware code for Tangent type cards. */
-#include "cops_ffdrv.h"		/* Firmware code for Dayna type cards. */
-
-/*
- *      The name of the card. Is used for messages and in the requests for
- *      io regions, irqs and dma channels
- */
-
-static const char *cardname = "cops";
-
-#ifdef CONFIG_COPS_DAYNA
-static int board_type = DAYNA;	/* Module exported */
-#else
-static int board_type = TANGENT;
-#endif
-
-#ifdef MODULE
-static int io = 0x240;		/* Default IO for Dayna */
-static int irq = 5;		/* Default IRQ */
-#else
-static int io = 0;		/* Default IO for Dayna */
-static int irq = 0;		/* Default IRQ */
-#endif
-
-/*
- *	COPS Autoprobe information.
- *	Right now if port address is right but IRQ is not 5 this will
- *      return a 5 no matter what since we will still get a status response.
- *      Need one more additional check to narrow down after we have gotten
- *      the ioaddr. But since only other possible IRQs is 3 and 4 so no real
- *	hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with
- *	this driver.
- * 
- *	This driver has 2 modes and they are: Dayna mode and Tangent mode.
- *	Each mode corresponds with the type of card. It has been found
- *	that there are 2 main types of cards and all other cards are
- *	the same and just have different names or only have minor differences
- *	such as more IO ports. As this driver is tested it will
- *	become more clear on exactly what cards are supported. The driver
- *	defaults to using Dayna mode. To change the drivers mode, simply
- *	select Dayna or Tangent mode when configuring the kernel.
- *
- *      This driver should support:
- *      TANGENT driver mode:
- *              Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200,
- *		COPS LT-1
- *      DAYNA driver mode:
- *              Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, 
- *		Farallon PhoneNET PC III, Farallon PhoneNET PC II
- *	Other cards possibly supported mode unkown though:
- *		Dayna DL2000 (Full length), COPS LT/M (Micro-Channel)
- *
- *	Cards NOT supported by this driver but supported by the ltpc.c
- *	driver written by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *		Farallon PhoneNET PC
- *		Original Apple LocalTalk PC card
- * 
- *      N.B.
- *
- *      The Daystar Digital LT200 boards do not support interrupt-driven
- *      IO.  You must specify 'irq=0xff' as a module parameter to invoke
- *      polled mode.  I also believe that the port probing logic is quite
- *      dangerous at best and certainly hopeless for a polled card.  Best to 
- *      specify both. - Steve H.
- *
- */
-
-/*
- * Zero terminated list of IO ports to probe.
- */
-
-static unsigned int cops_portlist[] = { 
-	0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 
-	0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360,
-	0
-};
-
-/*
- * Zero terminated list of IRQ ports to probe.
- */
-
-static int cops_irqlist[] = {
-	5, 4, 3, 0 
-};
-
-static struct timer_list cops_timer;
-
-/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef COPS_DEBUG
-#define COPS_DEBUG 1 
-#endif
-static unsigned int cops_debug = COPS_DEBUG;
-
-/* The number of low I/O ports used by the card. */
-#define COPS_IO_EXTENT       8
-
-/* Information that needs to be kept for each board. */
-
-struct cops_local
-{
-        struct net_device_stats stats;
-        int board;			/* Holds what board type is. */
-	int nodeid;			/* Set to 1 once have nodeid. */
-        unsigned char node_acquire;	/* Node ID when acquired. */
-        struct at_addr node_addr;	/* Full node addres */
-};
-
-/* Index to functions, as function prototypes. */
-extern int  cops_probe (struct net_device *dev);
-static int  cops_probe1 (struct net_device *dev, int ioaddr);
-static int  cops_irq (int ioaddr, int board);
-
-static int  cops_open (struct net_device *dev);
-static int  cops_jumpstart (struct net_device *dev);
-static void cops_reset (struct net_device *dev, int sleep);
-static void cops_load (struct net_device *dev);
-static int  cops_nodeid (struct net_device *dev, int nodeid);
-
-static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static void cops_poll (unsigned long ltdev);
-static void cops_timeout(struct net_device *dev);
-static void cops_rx (struct net_device *dev);
-static int  cops_send_packet (struct sk_buff *skb, struct net_device *dev);
-static void set_multicast_list (struct net_device *dev);
-static int  cops_hard_header (struct sk_buff *skb, struct net_device *dev,
-			      unsigned short type, void *daddr, void *saddr, 
-			      unsigned len);
-
-static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static int  cops_close (struct net_device *dev);
-static struct net_device_stats *cops_get_stats (struct net_device *dev);
-
-
-/*
- *      Check for a network adaptor of this type, and return '0' iff one exists.
- *      If dev->base_addr == 0, probe all likely locations.
- *      If dev->base_addr in [1..0x1ff], always return failure.
- *        otherwise go with what we pass in.
- */
-int __init cops_probe(struct net_device *dev)
-{
-	int i;
-        int base_addr = dev ? dev->base_addr : 0;
-        
-        if(base_addr == 0 && io)
-        	base_addr=io;
-
-        if(base_addr > 0x1ff)    /* Check a single specified location. */
-                return cops_probe1(dev, base_addr);
-	else if(base_addr != 0)  /* Don't probe at all. */
-               	return -ENXIO;
-	
-	/* FIXME  Does this really work for cards which generate irq?
-	 * It's definitely N.G. for polled Tangent. sh
-	 * Dayna cards don't autoprobe well at all, but if your card is
-	 * at IRQ 5 & IO 0x240 we find it every time. ;) JS
-	 */
-        for(i=0; cops_portlist[i]; i++) {
-		int ioaddr = cops_portlist[i];
-		if(check_region(ioaddr, COPS_IO_EXTENT))
-                        continue;
-                if(cops_probe1(dev, ioaddr) == 0)
-                        return 0;
-        }
-	
-        return -ENODEV;
-}
-
-/*
- *      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.
- */
-static int __init cops_probe1(struct net_device *dev, int ioaddr)
-{
-        struct cops_local *lp;
-	static unsigned version_printed = 0;
-
-	int board = board_type;
-	
-        if(cops_debug && version_printed++ == 0)
-		printk("%s", version);
-
-        /*
-         * Since this board has jumpered interrupts, allocate the interrupt
-         * vector now. There is no point in waiting since no other device
-         * can use the interrupt, and this marks the irq as busy. Jumpered
-         * interrupts are typically not reported by the boards, and we must
-         * used AutoIRQ to find them.
-	 */
-	switch (dev->irq)
-	{
-		case 0:
-			/* COPS AutoIRQ routine */
-			dev->irq = cops_irq(ioaddr, board);
-			if(!dev->irq)
-				return -EINVAL;	/* No IRQ found on this port */
-			break;
-
-		case 1:
-			return -EINVAL;
-			break;
-
-		/* Fixup for users that don't know that IRQ 2 is really
-		 * IRQ 9, or don't know which one to set.
-		 */
-		case 2:
-			dev->irq = 9;
-			break;
-
-		/* Polled operation requested. Although irq of zero passed as
-		 * a parameter tells the init routines to probe, we'll
-		 * overload it to denote polled operation at runtime.
-		 */
-		case 0xff:
-			dev->irq = 0;
-			break;
-
-		default:
-			break;
-	}
-
-	/* Reserve any actual interrupt. */
-	if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev))
-		return -EINVAL;
-
-	/* Grab the region so no one else tries to probe our ioports. */
-	request_region(ioaddr, COPS_IO_EXTENT, cardname);
-	dev->base_addr          = ioaddr;
-
-	/* Initialize the private device structure. */
-        dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL);
-        if(dev->priv == NULL)
-        	return -ENOMEM;
-
-        lp = (struct cops_local *)dev->priv;
-        memset(lp, 0, sizeof(struct cops_local));
-
-	/* Copy local board variable to lp struct. */
-	lp->board               = board;
-
-	/* Fill in the fields of the device structure with LocalTalk values. */
-	ltalk_setup(dev);
-
-	dev->hard_start_xmit    = cops_send_packet;
-	dev->tx_timeout		= cops_timeout;
-	dev->watchdog_timeo	= HZ * 2;
-	dev->hard_header	= cops_hard_header;
-        dev->get_stats          = cops_get_stats;
-	dev->open               = cops_open;
-        dev->stop               = cops_close;
-        dev->do_ioctl           = cops_ioctl;
-	dev->set_multicast_list = set_multicast_list;
-        dev->mc_list            = NULL;
-
-	/* Tell the user where the card is and what mode we're in. */
-	if(board==DAYNA)
-		printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", 
-			dev->name, cardname, ioaddr, dev->irq);
-	if(board==TANGENT) {
-		if(dev->irq)
-			printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", 
-				dev->name, cardname, ioaddr, dev->irq);
-		else
-			printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", 
-				dev->name, cardname, ioaddr);
-
-	}
-        return 0;
-}
-
-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.
-         * This really just verifies the IO port but since we only have access
-         * to such a small number of IRQs (5, 4, 3) this is not bad.
-         * This will probably not work for more than one card.
-         */
-        int irqaddr=0;
-        int i, x, status;
-
-        if(board==DAYNA)
-        {
-                outb(0, ioaddr+DAYNA_RESET);
-                inb(ioaddr+DAYNA_RESET);
-                udelay(333333);
-        }
-        if(board==TANGENT)
-        {
-                inb(ioaddr);
-                outb(0, ioaddr);
-                outb(0, ioaddr+TANG_RESET);
-        }
-
-        for(i=0; cops_irqlist[i] !=0; i++)
-        {
-                irqaddr = cops_irqlist[i];
-                for(x = 0xFFFF; x>0; x --)    /* wait for response */
-                {
-                        if(board==DAYNA)
-                        {
-                                status = (inb(ioaddr+DAYNA_CARD_STATUS)&3);
-                                if(status == 1)
-                                        return irqaddr;
-                        }
-                        if(board==TANGENT)
-                        {
-                                if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0)
-                                        return irqaddr;
-                        }
-                }
-        }
-        return 0;       /* no IRQ found */
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- */
-static int cops_open(struct net_device *dev)
-{
-    struct cops_local *lp = (struct cops_local *)dev->priv;
-
-	if(dev->irq==0)
-	{
-		/*
-		 * I don't know if the Dayna-style boards support polled 
-		 * operation.  For now, only allow it for Tangent.
-		 */
-		if(lp->board==TANGENT)	/* Poll 20 times per second */
-		{
-		    init_timer(&cops_timer);
-		    cops_timer.function = cops_poll;
-		    cops_timer.data 	= (unsigned long)dev;
-		    cops_timer.expires 	= jiffies + 5;
-		    add_timer(&cops_timer);
-		} 
-		else 
-		{
-			printk(KERN_WARNING "%s: No irq line set\n", dev->name);
-			return -EAGAIN;
-		}
-	}
-
-	cops_jumpstart(dev);	/* Start the card up. */
-
-	netif_start_queue(dev);
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
-
-        return 0;
-}
-
-/*
- *	This allows for a dynamic start/restart of the entire card.
- */
-static int cops_jumpstart(struct net_device *dev)
-{
-	struct cops_local *lp = (struct cops_local *)dev->priv;
-
-	/*
-         *      Once the card has the firmware loaded and has acquired
-         *      the nodeid, if it is reset it will lose it all.
-         */
-        cops_reset(dev,1);	/* Need to reset card before load firmware. */
-        cops_load(dev);		/* Load the firmware. */
-
-	/*
-	 *	If atalkd already gave us a nodeid we will use that
-	 *	one again, else we wait for atalkd to give us a nodeid
-	 *	in cops_ioctl. This may cause a problem if someone steals
-	 *	our nodeid while we are resetting.
-	 */	
-	if(lp->nodeid == 1)
-		cops_nodeid(dev,lp->node_acquire);
-
-	return 0;
-}
-
-static void tangent_wait_reset(int ioaddr)
-{
-	int timeout=0;
-
-	while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-		mdelay(1);   /* Wait 1 second */
-}
-
-/*
- *      Reset the LocalTalk board.
- */
-static void cops_reset(struct net_device *dev, int sleep)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr=dev->base_addr;
-
-        if(lp->board==TANGENT)
-        {
-                inb(ioaddr);		/* Clear request latch. */
-                outb(0,ioaddr);		/* Clear the TANG_TX_READY flop. */
-                outb(0, ioaddr+TANG_RESET);	/* Reset the adapter. */
-
-		tangent_wait_reset(ioaddr);
-                outb(0, ioaddr+TANG_CLEAR_INT);
-        }
-        if(lp->board==DAYNA)
-        {
-                outb(0, ioaddr+DAYNA_RESET);	/* Assert the reset port */
-                inb(ioaddr+DAYNA_RESET);	/* Clear the reset */
-                if(sleep)
-                {
-                        long snap=jiffies;
-
-			/* Let card finish initializing, about 1/3 second */
-	                while(jiffies-snap<HZ/3)
-                                schedule();
-                }
-                else
-                        udelay(333333);
-        }
-	netif_wake_queue(dev);
-	return;
-}
-
-static void cops_load (struct net_device *dev)
-{
-        struct ifreq ifr;
-        struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data;
-        struct cops_local *lp=(struct cops_local *)dev->priv;
-        int ioaddr=dev->base_addr;
-	int length, i = 0;
-
-        strcpy(ifr.ifr_name,"lt0");
-
-        /* Get card's firmware code and do some checks on it. */
-#ifdef CONFIG_COPS_DAYNA        
-        if(lp->board==DAYNA)
-        {
-                ltf->length=sizeof(ffdrv_code);
-                ltf->data=ffdrv_code;
-        }
-        else
-#endif        
-#ifdef CONFIG_COPS_TANGENT
-        if(lp->board==TANGENT)
-        {
-                ltf->length=sizeof(ltdrv_code);
-                ltf->data=ltdrv_code;
-        }
-        else
-#endif
-	{
-		printk(KERN_INFO "%s; unsupported board type.\n", dev->name);
-		return;
-	}
-	
-        /* Check to make sure firmware is correct length. */
-        if(lp->board==DAYNA && ltf->length!=5983)
-        {
-                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);
-                return;
-        }
-        if(lp->board==TANGENT && ltf->length!=2501)
-        {
-                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);
-                return;
-        }
-
-        if(lp->board==DAYNA)
-        {
-                /*
-                 *      We must wait for a status response
-                 *      with the DAYNA board.
-                 */
-                while(++i<65536)
-                {
-                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)
-                                break;
-                }
-
-                if(i==65536)
-                        return;
-        }
-
-        /*
-         *      Upload the firmware and kick. Byte-by-byte works nicely here.
-         */
-	i=0;
-        length = ltf->length;
-        while(length--)
-        {
-                outb(ltf->data[i], ioaddr);
-                i++;
-        }
-
-	if(cops_debug > 1)
-		printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 
-			dev->name, i, ltf->length);
-
-        if(lp->board==DAYNA) 	/* Tell Dayna to run the firmware code. */
-                outb(1, ioaddr+DAYNA_INT_CARD);
-	else			/* Tell Tang to run the firmware code. */
-		inb(ioaddr);
-
-        if(lp->board==TANGENT)
-        {
-                tangent_wait_reset(ioaddr);
-                inb(ioaddr);	/* Clear initial ready signal. */
-        }
-
-        return;
-}
-
-/*
- * 	Get the LocalTalk Nodeid from the card. We can suggest
- *	any nodeid 1-254. The card will try and get that exact
- *	address else we can specify 0 as the nodeid and the card
- *	will autoprobe for a nodeid.
- */
-static int cops_nodeid (struct net_device *dev, int nodeid)
-{
-	struct cops_local *lp = (struct cops_local *) dev->priv;
-	int ioaddr = dev->base_addr;
-
-	if(lp->board == DAYNA)
-        {
-        	/* Empty any pending adapter responses. */
-                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
-                {
-			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupts. */
-        		if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
-                		cops_rx(dev);	/* Kick any packets waiting. */
-			schedule();
-                }
-
-                outb(2, ioaddr);       	/* Output command packet length as 2. */
-                outb(0, ioaddr);
-                outb(LAP_INIT, ioaddr);	/* Send LAP_INIT command byte. */
-                outb(nodeid, ioaddr);  	/* Suggest node address. */
-        }
-
-	if(lp->board == TANGENT)
-        {
-                /* Empty any pending adapter responses. */
-                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
-                {
-			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupt. */
-                	cops_rx(dev);          	/* Kick out packets waiting. */
-			schedule();
-                }
-
-		/* Not sure what Tangent does if nodeid picked is used. */
-                if(nodeid == 0)	         		/* Seed. */
-                	nodeid = jiffies&0xFF;		/* Get a random try */
-                outb(2, ioaddr);        		/* Command length LSB */
-                outb(0, ioaddr);       			/* Command length MSB */
-                outb(LAP_INIT, ioaddr); 		/* Send LAP_INIT byte */
-                outb(nodeid, ioaddr); 		  	/* LAP address hint. */
-                outb(0xFF, ioaddr);     		/* Int. level to use */
-        }
-
-	lp->node_acquire=0;		/* Set nodeid holder to 0. */
-        while(lp->node_acquire==0)	/* Get *True* nodeid finally. */
-	{
-		outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear any interrupt. */
-
-		if(lp->board == DAYNA)
-		{
-                	if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
-                		cops_rx(dev);	/* Grab the nodeid put in lp->node_acquire. */
-		}
-		if(lp->board == TANGENT)
-		{	
-			if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
-                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */
-		}
-		schedule();
-	}
-
-	if(cops_debug > 1)
-		printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 
-			dev->name, lp->node_acquire);
-
-	lp->nodeid=1;	/* Set got nodeid to 1. */
-
-        return 0;
-}
-
-/*
- *	Poll the Tangent type cards to see if we have work.
- */
- 
-static void cops_poll(unsigned long ltdev)
-{
-	int ioaddr, status;
-	int boguscount = 0;
-
-	struct net_device *dev = (struct net_device *)ltdev;
-
-	del_timer(&cops_timer);
-
-	if(dev == NULL)
-		return;	/* We've been downed */
-
-	ioaddr = dev->base_addr;
-	do {
-		status=inb(ioaddr+TANG_CARD_STATUS);
-		if(status & TANG_RX_READY)
-			cops_rx(dev);
-		if(status & TANG_TX_READY)
-			netif_wake_queue(dev);
-		status = inb(ioaddr+TANG_CARD_STATUS);
-	} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
-
-	cops_timer.expires = jiffies+5;
-	add_timer(&cops_timer);
-
-	return;
-}
-
-/*
- *      The typical workload of the driver:
- *      Handle the network interface interrupts.
- */
-static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-        struct net_device *dev = dev_id;
-        struct cops_local *lp;
-        int ioaddr, status;
-        int boguscount = 0;
-
-        ioaddr = dev->base_addr;
-        lp = (struct cops_local *)dev->priv;
-
-	if(lp->board==DAYNA)
-	{
-		do {
-			outb(0, ioaddr + COPS_CLEAR_INT);
-                       	status=inb(ioaddr+DAYNA_CARD_STATUS);
-                       	if((status&0x03)==DAYNA_RX_REQUEST)
-                       	        cops_rx(dev);
-                	netif_wake_queue(dev);
-		} while(++boguscount < 20);
-	}
-	else
-	{
-		do {
-                       	status=inb(ioaddr+TANG_CARD_STATUS);
-			if(status & TANG_RX_READY)
-				cops_rx(dev);
-			if(status & TANG_TX_READY)
-				netif_wake_queue(dev);
-			status=inb(ioaddr+TANG_CARD_STATUS);
-		} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
-	}
-
-        return;
-}
-
-/*
- *      We have a good packet(s), get it/them out of the buffers.
- */
-static void cops_rx(struct net_device *dev)
-{
-        int pkt_len = 0;
-        int rsp_type = 0;
-        struct sk_buff *skb;
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr = dev->base_addr;
-        int boguscount = 0;
-        unsigned long flags;
-
-
-	save_flags(flags);
-        cli();  /* Disable interrupts. */
-
-        if(lp->board==DAYNA)
-        {
-                outb(0, ioaddr);                /* Send out Zero length. */
-                outb(0, ioaddr);
-                outb(DATA_READ, ioaddr);        /* Send read command out. */
-
-                /* Wait for DMA to turn around. */
-                while(++boguscount<1000000)
-                {
-                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
-                                break;
-                }
-
-                if(boguscount==1000000)
-                {
-                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);
-                        return;
-                }
-        }
-
-        /* Get response length. */
-	if(lp->board==DAYNA)
-        	pkt_len = inb(ioaddr) & 0xFF;
-	else
-		pkt_len = inb(ioaddr) & 0x00FF;
-        pkt_len |= (inb(ioaddr) << 8);
-        /* Input IO code. */
-        rsp_type=inb(ioaddr);
-
-        /* Malloc up new buffer. */
-        skb = dev_alloc_skb(pkt_len);
-        if(skb == NULL)
-        {
-                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
-			dev->name);
-                lp->stats.rx_dropped++;
-                while(pkt_len--)        /* Discard packet */
-                        inb(ioaddr);
-                return;
-        }
-        skb->dev = dev;
-        skb_put(skb, pkt_len);
-        skb->protocol = htons(ETH_P_LOCALTALK);
-
-        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */
-
-        if(lp->board==DAYNA)
-                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */
-
-        restore_flags(flags);  /* Restore interrupts. */
-
-        /* Check for bad response length */
-        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
-        {
-		printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
-			dev->name, pkt_len);
-                lp->stats.tx_errors++;
-                kfree_skb(skb);
-                return;
-        }
-
-        /* Set nodeid and then get out. */
-        if(rsp_type == LAP_INIT_RSP)
-        {	/* Nodeid taken from received packet. */
-                lp->node_acquire = skb->data[0];
-                kfree_skb(skb);
-                return;
-        }
-
-        /* One last check to make sure we have a good packet. */
-        if(rsp_type != LAP_RESPONSE)
-        {
-                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
-                lp->stats.tx_errors++;
-                kfree_skb(skb);
-                return;
-        }
-
-        skb->mac.raw    = skb->data;    /* Point to entire packet. */
-        skb_pull(skb,3);
-        skb->h.raw      = skb->data;    /* Point to data (Skip header). */
-
-        /* Update the counters. */
-        lp->stats.rx_packets++;
-        lp->stats.rx_bytes += skb->len;
-
-        /* Send packet to a higher place. */
-        netif_rx(skb);
-
-        return;
-}
-
-static void cops_timeout(struct net_device *dev)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr = dev->base_addr;
-
-	lp->stats.tx_errors++;
-        if(lp->board==TANGENT)
-        {
-		if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
-               		printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
-	}
-	printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
-	cops_jumpstart(dev);	/* Restart the card. */
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
-}
-
-
-/*
- *	Make the card transmit a LocalTalk packet.
- */
-
-static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        int ioaddr = dev->base_addr;
-        unsigned long flags;
-
-        /*
-         * Block a timer-based transmit from overlapping. 
-	 */
-	 
-	netif_stop_queue(dev);
-
-	save_flags(flags);	
-	cli();	/* Disable interrupts. */
-	if(lp->board == DAYNA)	 /* Wait for adapter transmit buffer. */
-		while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
-	if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
-		while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
-
-	/* Output IO length. */
-	outb(skb->len, ioaddr);
-	if(lp->board == DAYNA)
-               	outb(skb->len >> 8, ioaddr);
-	else
-		outb((skb->len >> 8)&0x0FF, ioaddr);
-
-	/* Output IO code. */
-	outb(LAP_WRITE, ioaddr);
-
-	if(lp->board == DAYNA)	/* Check the transmit buffer again. */
-        	while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
-
-	outsb(ioaddr, skb->data, skb->len);	/* Send out the data. */
-
-	if(lp->board==DAYNA)	/* Dayna requires you kick the card */
-		outb(1, ioaddr+DAYNA_INT_CARD);
-
-	restore_flags(flags);	/* Restore interrupts. */
-
-	/* Done sending packet, update counters and cleanup. */
-	lp->stats.tx_packets++;
-	lp->stats.tx_bytes += skb->len;
-	dev->trans_start = jiffies;
-	dev_kfree_skb (skb);
-        return 0;
-}
-
-/*
- *	Dummy function to keep the Appletalk layer happy.
- */
- 
-static void set_multicast_list(struct net_device *dev)
-{
-        if(cops_debug >= 3)
-		printk("%s: set_multicast_list executed\n", dev->name);
-}
-
-/*
- *      Another Dummy function to keep the Appletalk layer happy.
- */
- 
-static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr, 
-			    unsigned len)
-{
-        if(cops_debug >= 3)
-                printk("%s: cops_hard_header executed. Wow!\n", dev->name);
-        return 0;
-}
-
-/*
- *      System ioctls for the COPS LocalTalk card.
- */
- 
-static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr;
-        struct at_addr *aa=(struct at_addr *)&lp->node_addr;
-
-        switch(cmd)
-        {
-                case SIOCSIFADDR:
-			/* Get and set the nodeid and network # atalkd wants. */
-			cops_nodeid(dev, sa->sat_addr.s_node);
-			aa->s_net               = sa->sat_addr.s_net;
-                        aa->s_node              = lp->node_acquire;
-
-			/* Set broardcast address. */
-                        dev->broadcast[0]       = 0xFF;
-			
-			/* Set hardware address. */
-                        dev->dev_addr[0]        = aa->s_node;
-                        dev->addr_len           = 1;
-                        return 0;
-
-                case SIOCGIFADDR:
-                        sa->sat_addr.s_net      = aa->s_net;
-                        sa->sat_addr.s_node     = aa->s_node;
-                        return 0;
-
-                default:
-                        return -EOPNOTSUPP;
-        }
-}
-
-/*
- *	The inverse routine to cops_open().
- */
- 
-static int cops_close(struct net_device *dev)
-{
-	struct cops_local *lp = (struct cops_local *)dev->priv;
-
-	/* If we were running polled, yank the timer.
-	 */
-	if(lp->board==TANGENT && dev->irq==0)
-		del_timer(&cops_timer);
-
-	netif_stop_queue(dev);
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
-	
-        return 0;
-}
-
-/*
- *      Get the current statistics.
- *      This may be called with the card open or closed.
- */
-static struct net_device_stats *cops_get_stats(struct net_device *dev)
-{
-        struct cops_local *lp = (struct cops_local *)dev->priv;
-        return &lp->stats;
-}
-
-#ifdef MODULE
-static char lt_name[16];
-
-static struct net_device cops0_dev =
-{
-	lt_name,	/* device name */
-        0, 0, 0, 0,
-        0x0, 0,  /* I/O address, IRQ */
-        0, 0, 0, NULL, cops_probe
-};
-
-
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(board_type, "i");
-
-int init_module(void)
-{
-        int result, err;
-
-        if(io == 0)
-		printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
-			cardname);
-
-        /* Copy the parameters from insmod into the device structure. */
-        cops0_dev.base_addr = io;
-        cops0_dev.irq       = irq;
-
-	err=dev_alloc_name(&cops0_dev, "lt%d");
-        if(err < 0)
-                return err;
-
-        if((result = register_netdev(&cops0_dev)) != 0)
-                return result;
-
-        return 0;
-}
-
-void cleanup_module(void)
-{
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	unregister_netdev(&cops0_dev);
-	if(cops0_dev.priv)
-                kfree_s(cops0_dev.priv, sizeof(struct cops_local));
-	if(cops0_dev.irq)
-		free_irq(cops0_dev.irq, &cops0_dev);
-        release_region(cops0_dev.base_addr, COPS_IO_EXTENT);
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
- *  c-basic-offset: 4
- *  c-file-offsets: ((substatement-open . 0))
- * End:
- */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops.h linux/drivers/net/cops.h
--- v2.3.49/linux/drivers/net/cops.h	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/cops.h	Wed Dec 31 16:00:00 1969
@@ -1,60 +0,0 @@
-/*      cops.h: LocalTalk driver for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- */
-
-#ifndef __LINUX_COPSLTALK_H
-#define __LINUX_COPSLTALK_H
-
-#ifdef __KERNEL__
-
-/* Max LLAP size we will accept. */
-#define MAX_LLAP_SIZE		603
-
-/* Tangent */
-#define TANG_CARD_STATUS        1
-#define TANG_CLEAR_INT          1
-#define TANG_RESET              3
-
-#define TANG_TX_READY           1
-#define TANG_RX_READY           2
-
-/* Dayna */
-#define DAYNA_CMD_DATA          0
-#define DAYNA_CLEAR_INT         1
-#define DAYNA_CARD_STATUS       2
-#define DAYNA_INT_CARD          3
-#define DAYNA_RESET             4
-
-#define DAYNA_RX_READY          0
-#define DAYNA_TX_READY          1
-#define DAYNA_RX_REQUEST        3
-
-/* Same on both card types */
-#define COPS_CLEAR_INT  1
-
-/* LAP response codes received from the cards. */
-#define LAP_INIT        1       /* Init cmd */
-#define LAP_INIT_RSP    2       /* Init response */
-#define LAP_WRITE       3       /* Write cmd */
-#define DATA_READ       4       /* Data read */
-#define LAP_RESPONSE    4       /* Received ALAP frame response */
-#define LAP_GETSTAT     5       /* Get LAP and HW status */
-#define LAP_RSPSTAT     6       /* Status response */
-
-#endif
-
-/*
- *	Structure to hold the firmware information.
- */
-struct ltfirmware
-{
-        unsigned int length;
-        unsigned char * data;
-};
-
-#define DAYNA 1
-#define TANGENT 2
-
-#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops_ffdrv.h linux/drivers/net/cops_ffdrv.h
--- v2.3.49/linux/drivers/net/cops_ffdrv.h	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/cops_ffdrv.h	Wed Dec 31 16:00:00 1969
@@ -1,533 +0,0 @@
-
-/*
- *	The firmware this driver downloads into the Localtalk card is a
- *	separate program and is not GPL'd source code, even though the Linux
- *	side driver and the routine that loads this data into the card are.
- *	
- *	It is taken from the COPS SDK and is under the following license
- *
- *	This material is licensed to you strictly for use in conjunction with
- *	the use of COPS LocalTalk adapters.
- *	There is no charge for this SDK. And no waranty express or implied
- *	about its fitness for any purpose. However, we will cheerefully
- *	refund every penny you paid for this SDK...
- *	Regards,
- *
- *	Thomas F. Divine
- *	Chief Scientist
- */
-
-
-/*      cops_ffdrv.h: LocalTalk driver firmware dump for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- */
-
-#include <linux/config.h>
-
-#ifdef CONFIG_COPS_DAYNA
-
-unsigned char ffdrv_code[] = {
-	58,3,0,50,228,149,33,255,255,34,226,149,
-	249,17,40,152,33,202,154,183,237,82,77,68,
-	11,107,98,19,54,0,237,176,175,50,80,0,
-	62,128,237,71,62,32,237,57,51,62,12,237,
-	57,50,237,57,54,62,6,237,57,52,62,12,
-	237,57,49,33,107,137,34,32,128,33,83,130,
-	34,40,128,33,86,130,34,42,128,33,112,130,
-	34,36,128,33,211,130,34,38,128,62,0,237,
-	57,16,33,63,148,34,34,128,237,94,205,15,
-	130,251,205,168,145,24,141,67,111,112,121,114,
-	105,103,104,116,32,40,67,41,32,49,57,56,
-	56,32,45,32,68,97,121,110,97,32,67,111,
-	109,109,117,110,105,99,97,116,105,111,110,115,
-	32,32,32,65,108,108,32,114,105,103,104,116,
-	115,32,114,101,115,101,114,118,101,100,46,32,
-	32,40,68,40,68,7,16,8,34,7,22,6,
-	16,5,12,4,8,3,6,140,0,16,39,128,
-	0,4,96,10,224,6,0,7,126,2,64,11,
-	118,12,6,13,0,14,193,15,0,5,96,3,
-	192,1,64,9,8,62,9,211,66,62,192,211,
-	66,62,100,61,32,253,6,28,33,205,129,14,
-	66,237,163,194,253,129,6,28,33,205,129,14,
-	64,237,163,194,9,130,201,62,47,50,71,152,
-	62,47,211,68,58,203,129,237,57,20,58,204,
-	129,237,57,21,33,77,152,54,132,205,233,129,
-	58,228,149,254,209,40,6,56,4,62,0,24,
-	2,219,96,33,233,149,119,230,62,33,232,149,
-	119,213,33,8,152,17,7,0,25,119,19,25,
-	119,209,201,251,237,77,245,197,213,229,221,229,
-	205,233,129,62,1,50,106,137,205,158,139,221,
-	225,225,209,193,241,251,237,77,245,197,213,219,
-	72,237,56,16,230,46,237,57,16,237,56,12,
-	58,72,152,183,32,26,6,20,17,128,2,237,
-	56,46,187,32,35,237,56,47,186,32,29,219,
-	72,230,1,32,3,5,32,232,175,50,72,152,
-	229,221,229,62,1,50,106,137,205,158,139,221,
-	225,225,24,25,62,1,50,72,152,58,201,129,
-	237,57,12,58,202,129,237,57,13,237,56,16,
-	246,17,237,57,16,209,193,241,251,237,77,245,
-	197,229,213,221,229,237,56,16,230,17,237,57,
-	16,237,56,20,58,34,152,246,16,246,8,211,
-	68,62,6,61,32,253,58,34,152,246,8,211,
-	68,58,203,129,237,57,20,58,204,129,237,57,
-	21,237,56,16,246,34,237,57,16,221,225,209,
-	225,193,241,251,237,77,33,2,0,57,126,230,
-	3,237,100,1,40,2,246,128,230,130,245,62,
-	5,211,64,241,211,64,201,229,213,243,237,56,
-	16,230,46,237,57,16,237,56,12,251,70,35,
-	35,126,254,175,202,77,133,254,129,202,15,133,
-	230,128,194,191,132,43,58,44,152,119,33,76,
-	152,119,35,62,132,119,120,254,255,40,4,58,
-	49,152,119,219,72,43,43,112,17,3,0,237,
-	56,52,230,248,237,57,52,219,72,230,1,194,
-	141,131,209,225,237,56,52,246,6,237,57,52,
-	62,1,55,251,201,62,3,211,66,62,192,211,
-	66,62,48,211,66,0,0,219,66,230,1,40,
-	4,219,67,24,240,205,203,135,58,75,152,254,
-	255,202,128,132,58,49,152,254,161,250,207,131,
-	58,34,152,211,68,62,10,211,66,62,128,211,
-	66,62,11,211,66,62,6,211,66,24,0,62,
-	14,211,66,62,33,211,66,62,1,211,66,62,
-	64,211,66,62,3,211,66,62,209,211,66,62,
-	100,71,219,66,230,1,32,6,5,32,247,195,
-	248,132,219,67,71,58,44,152,184,194,248,132,
-	62,100,71,219,66,230,1,32,6,5,32,247,
-	195,248,132,219,67,62,100,71,219,66,230,1,
-	32,6,5,32,247,195,248,132,219,67,254,133,
-	32,7,62,0,50,74,152,24,17,254,173,32,
-	7,62,1,50,74,152,24,6,254,141,194,248,
-	132,71,209,225,58,49,152,254,132,32,10,62,
-	50,205,2,134,205,144,135,24,27,254,140,32,
-	15,62,110,205,2,134,62,141,184,32,5,205,
-	144,135,24,8,62,10,205,2,134,205,8,134,
-	62,1,50,106,137,205,158,139,237,56,52,246,
-	6,237,57,52,175,183,251,201,62,20,135,237,
-	57,20,175,237,57,21,237,56,16,246,2,237,
-	57,16,237,56,20,95,237,56,21,123,254,10,
-	48,244,237,56,16,230,17,237,57,16,209,225,
-	205,144,135,62,1,50,106,137,205,158,139,237,
-	56,52,246,6,237,57,52,175,183,251,201,209,
-	225,243,219,72,230,1,40,13,62,10,211,66,
-	0,0,219,66,230,192,202,226,132,237,56,52,
-	246,6,237,57,52,62,1,55,251,201,205,203,
-	135,62,1,50,106,137,205,158,139,237,56,52,
-	246,6,237,57,52,183,251,201,209,225,62,1,
-	50,106,137,205,158,139,237,56,52,246,6,237,
-	57,52,62,2,55,251,201,209,225,243,219,72,
-	230,1,202,213,132,62,10,211,66,0,0,219,
-	66,230,192,194,213,132,229,62,1,50,106,137,
-	42,40,152,205,65,143,225,17,3,0,205,111,
-	136,62,6,211,66,58,44,152,211,66,237,56,
-	52,246,6,237,57,52,183,251,201,209,197,237,
-	56,52,230,248,237,57,52,219,72,230,1,32,
-	15,193,225,237,56,52,246,6,237,57,52,62,
-	1,55,251,201,14,23,58,37,152,254,0,40,
-	14,14,2,254,1,32,5,62,140,119,24,3,
-	62,132,119,43,43,197,205,203,135,193,62,1,
-	211,66,62,64,211,66,62,3,211,66,62,193,
-	211,66,62,100,203,39,71,219,66,230,1,32,
-	6,5,32,247,195,229,133,33,238,151,219,67,
-	71,58,44,152,184,194,229,133,119,62,100,71,
-	219,66,230,1,32,6,5,32,247,195,229,133,
-	219,67,35,119,13,32,234,193,225,62,1,50,
-	106,137,205,158,139,237,56,52,246,6,237,57,
-	52,175,183,251,201,33,234,151,35,35,62,255,
-	119,193,225,62,1,50,106,137,205,158,139,237,
-	56,52,246,6,237,57,52,175,251,201,243,61,
-	32,253,251,201,62,3,211,66,62,192,211,66,
-	58,49,152,254,140,32,19,197,229,213,17,181,
-	129,33,185,129,1,2,0,237,176,209,225,193,
-	24,27,229,213,33,187,129,58,49,152,230,15,
-	87,30,2,237,92,25,17,181,129,126,18,19,
-	35,126,18,209,225,58,34,152,246,8,211,68,
-	58,49,152,254,165,40,14,254,164,40,10,62,
-	10,211,66,62,224,211,66,24,25,58,74,152,
-	254,0,40,10,62,10,211,66,62,160,211,66,
-	24,8,62,10,211,66,62,128,211,66,62,11,
-	211,66,62,6,211,66,205,147,143,62,5,211,
-	66,62,224,211,66,62,5,211,66,62,96,211,
-	66,62,5,61,32,253,62,5,211,66,62,224,
-	211,66,62,14,61,32,253,62,5,211,66,62,
-	233,211,66,62,128,211,66,58,181,129,61,32,
-	253,62,1,211,66,62,192,211,66,1,254,19,
-	237,56,46,187,32,6,13,32,247,195,226,134,
-	62,192,211,66,0,0,219,66,203,119,40,250,
-	219,66,203,87,40,250,243,237,56,16,230,17,
-	237,57,16,237,56,20,251,62,5,211,66,62,
-	224,211,66,58,182,129,61,32,253,229,33,181,
-	129,58,183,129,203,63,119,35,58,184,129,119,
-	225,62,10,211,66,62,224,211,66,62,11,211,
-	66,62,118,211,66,62,47,211,68,62,5,211,
-	66,62,233,211,66,58,181,129,61,32,253,62,
-	5,211,66,62,224,211,66,58,182,129,61,32,
-	253,62,5,211,66,62,96,211,66,201,229,213,
-	58,50,152,230,15,87,30,2,237,92,33,187,
-	129,25,17,181,129,126,18,35,19,126,18,209,
-	225,58,71,152,246,8,211,68,58,50,152,254,
-	165,40,14,254,164,40,10,62,10,211,66,62,
-	224,211,66,24,8,62,10,211,66,62,128,211,
-	66,62,11,211,66,62,6,211,66,195,248,135,
-	62,3,211,66,62,192,211,66,197,229,213,17,
-	181,129,33,183,129,1,2,0,237,176,209,225,
-	193,62,47,211,68,62,10,211,66,62,224,211,
-	66,62,11,211,66,62,118,211,66,62,1,211,
-	66,62,0,211,66,205,147,143,195,16,136,62,
-	3,211,66,62,192,211,66,197,229,213,17,181,
-	129,33,183,129,1,2,0,237,176,209,225,193,
-	62,47,211,68,62,10,211,66,62,224,211,66,
-	62,11,211,66,62,118,211,66,205,147,143,62,
-	5,211,66,62,224,211,66,62,5,211,66,62,
-	96,211,66,62,5,61,32,253,62,5,211,66,
-	62,224,211,66,62,14,61,32,253,62,5,211,
-	66,62,233,211,66,62,128,211,66,58,181,129,
-	61,32,253,62,1,211,66,62,192,211,66,1,
-	254,19,237,56,46,187,32,6,13,32,247,195,
-	88,136,62,192,211,66,0,0,219,66,203,119,
-	40,250,219,66,203,87,40,250,62,5,211,66,
-	62,224,211,66,58,182,129,61,32,253,62,5,
-	211,66,62,96,211,66,201,197,14,67,6,0,
-	62,3,211,66,62,192,211,66,62,48,211,66,
-	0,0,219,66,230,1,40,4,219,67,24,240,
-	62,5,211,66,62,233,211,66,62,128,211,66,
-	58,181,129,61,32,253,237,163,29,62,192,211,
-	66,219,66,230,4,40,250,237,163,29,32,245,
-	219,66,230,4,40,250,62,255,71,219,66,230,
-	4,40,3,5,32,247,219,66,230,4,40,250,
-	62,5,211,66,62,224,211,66,58,182,129,61,
-	32,253,62,5,211,66,62,96,211,66,58,71,
-	152,254,1,202,18,137,62,16,211,66,62,56,
-	211,66,62,14,211,66,62,33,211,66,62,1,
-	211,66,62,248,211,66,237,56,48,246,153,230,
-	207,237,57,48,62,3,211,66,62,221,211,66,
-	193,201,58,71,152,211,68,62,10,211,66,62,
-	128,211,66,62,11,211,66,62,6,211,66,62,
-	6,211,66,58,44,152,211,66,62,16,211,66,
-	62,56,211,66,62,48,211,66,0,0,62,14,
-	211,66,62,33,211,66,62,1,211,66,62,248,
-	211,66,237,56,48,246,145,246,8,230,207,237,
-	57,48,62,3,211,66,62,221,211,66,193,201,
-	44,3,1,0,70,69,1,245,197,213,229,175,
-	50,72,152,237,56,16,230,46,237,57,16,237,
-	56,12,62,1,211,66,0,0,219,66,95,230,
-	160,32,3,195,20,139,123,230,96,194,72,139,
-	62,48,211,66,62,1,211,66,62,64,211,66,
-	237,91,40,152,205,207,143,25,43,55,237,82,
-	218,70,139,34,42,152,98,107,58,44,152,190,
-	194,210,138,35,35,62,130,190,194,200,137,62,
-	1,50,48,152,62,175,190,202,82,139,62,132,
-	190,32,44,50,50,152,62,47,50,71,152,229,
-	175,50,106,137,42,40,152,205,65,143,225,54,
-	133,43,70,58,44,152,119,43,112,17,3,0,
-	62,10,205,2,134,205,111,136,195,158,138,62,
-	140,190,32,19,50,50,152,58,233,149,230,4,
-	202,222,138,62,1,50,71,152,195,219,137,126,
-	254,160,250,185,138,254,166,242,185,138,50,50,
-	152,43,126,35,229,213,33,234,149,95,22,0,
-	25,126,254,132,40,18,254,140,40,14,58,50,
-	152,230,15,87,126,31,21,242,65,138,56,2,
-	175,119,58,50,152,230,15,87,58,233,149,230,
-	62,31,21,242,85,138,218,98,138,209,225,195,
-	20,139,58,50,152,33,100,137,230,15,95,22,
-	0,25,126,50,71,152,209,225,58,50,152,254,
-	164,250,135,138,58,73,152,254,0,40,4,54,
-	173,24,2,54,133,43,70,58,44,152,119,43,
-	112,17,3,0,205,70,135,175,50,106,137,205,
-	208,139,58,199,129,237,57,12,58,200,129,237,
-	57,13,237,56,16,246,17,237,57,16,225,209,
-	193,241,251,237,77,62,129,190,194,227,138,54,
-	130,43,70,58,44,152,119,43,112,17,3,0,
-	205,144,135,195,20,139,35,35,126,254,132,194,
-	227,138,175,50,106,137,205,158,139,24,42,58,
-	201,154,254,1,40,7,62,1,50,106,137,24,
-	237,58,106,137,254,1,202,222,138,62,128,166,
-	194,222,138,221,229,221,33,67,152,205,127,142,
-	205,109,144,221,225,225,209,193,241,251,237,77,
-	58,106,137,254,1,202,44,139,58,50,152,254,
-	164,250,44,139,58,73,152,238,1,50,73,152,
-	221,229,221,33,51,152,205,127,142,221,225,62,
-	1,50,106,137,205,158,139,195,13,139,24,208,
-	24,206,24,204,230,64,40,3,195,20,139,195,
-	20,139,43,126,33,8,152,119,35,58,44,152,
-	119,43,237,91,35,152,205,203,135,205,158,139,
-	195,13,139,175,50,78,152,62,3,211,66,62,
-	192,211,66,201,197,33,4,0,57,126,35,102,
-	111,62,1,50,106,137,219,72,205,141,139,193,
-	201,62,1,50,78,152,34,40,152,54,0,35,
-	35,54,0,195,163,139,58,78,152,183,200,229,
-	33,181,129,58,183,129,119,35,58,184,129,119,
-	225,62,47,211,68,62,14,211,66,62,193,211,
-	66,62,10,211,66,62,224,211,66,62,11,211,
-	66,62,118,211,66,195,3,140,58,78,152,183,
-	200,58,71,152,211,68,254,69,40,4,254,70,
-	32,17,58,73,152,254,0,40,10,62,10,211,
-	66,62,160,211,66,24,8,62,10,211,66,62,
-	128,211,66,62,11,211,66,62,6,211,66,62,
-	6,211,66,58,44,152,211,66,62,16,211,66,
-	62,56,211,66,62,48,211,66,0,0,219,66,
-	230,1,40,4,219,67,24,240,62,14,211,66,
-	62,33,211,66,42,40,152,205,65,143,62,1,
-	211,66,62,248,211,66,237,56,48,246,145,246,
-	8,230,207,237,57,48,62,3,211,66,62,221,
-	211,66,201,62,16,211,66,62,56,211,66,62,
-	48,211,66,0,0,219,66,230,1,40,4,219,
-	67,24,240,62,14,211,66,62,33,211,66,62,
-	1,211,66,62,248,211,66,237,56,48,246,153,
-	230,207,237,57,48,62,3,211,66,62,221,211,
-	66,201,229,213,33,234,149,95,22,0,25,126,
-	254,132,40,4,254,140,32,2,175,119,123,209,
-	225,201,6,8,14,0,31,48,1,12,16,250,
-	121,201,33,4,0,57,94,35,86,33,2,0,
-	57,126,35,102,111,221,229,34,89,152,237,83,
-	91,152,221,33,63,152,205,127,142,58,81,152,
-	50,82,152,58,80,152,135,50,80,152,205,162,
-	140,254,3,56,16,58,81,152,135,60,230,15,
-	50,81,152,175,50,80,152,24,23,58,79,152,
-	205,162,140,254,3,48,13,58,81,152,203,63,
-	50,81,152,62,255,50,79,152,58,81,152,50,
-	82,152,58,79,152,135,50,79,152,62,32,50,
-	83,152,50,84,152,237,56,16,230,17,237,57,
-	16,219,72,62,192,50,93,152,62,93,50,94,
-	152,58,93,152,61,50,93,152,32,9,58,94,
-	152,61,50,94,152,40,44,62,170,237,57,20,
-	175,237,57,21,237,56,16,246,2,237,57,16,
-	219,72,230,1,202,29,141,237,56,20,71,237,
-	56,21,120,254,10,48,237,237,56,16,230,17,
-	237,57,16,243,62,14,211,66,62,65,211,66,
-	251,58,39,152,23,23,60,50,39,152,71,58,
-	82,152,160,230,15,40,22,71,14,10,219,66,
-	230,16,202,186,141,219,72,230,1,202,186,141,
-	13,32,239,16,235,42,89,152,237,91,91,152,
-	205,47,131,48,7,61,202,186,141,195,227,141,
-	221,225,33,0,0,201,221,33,55,152,205,127,
-	142,58,84,152,61,50,84,152,40,19,58,82,
-	152,246,1,50,82,152,58,79,152,246,1,50,
-	79,152,195,29,141,221,225,33,1,0,201,221,
-	33,59,152,205,127,142,58,80,152,246,1,50,
-	80,152,58,82,152,135,246,1,50,82,152,58,
-	83,152,61,50,83,152,194,29,141,221,225,33,
-	2,0,201,221,229,33,0,0,57,17,4,0,
-	25,126,50,44,152,230,128,50,85,152,58,85,
-	152,183,40,6,221,33,88,2,24,4,221,33,
-	150,0,58,44,152,183,40,53,60,40,50,60,
-	40,47,61,61,33,86,152,119,35,119,35,54,
-	129,175,50,48,152,221,43,221,229,225,124,181,
-	40,42,33,86,152,17,3,0,205,189,140,17,
-	232,3,27,123,178,32,251,58,48,152,183,40,
-	224,58,44,152,71,62,7,128,230,127,71,58,
-	85,152,176,50,44,152,24,162,221,225,201,183,
-	221,52,0,192,221,52,1,192,221,52,2,192,
-	221,52,3,192,55,201,245,62,1,211,100,241,
-	201,245,62,1,211,96,241,201,33,2,0,57,
-	126,35,102,111,237,56,48,230,175,237,57,48,
-	62,48,237,57,49,125,237,57,32,124,237,57,
-	33,62,0,237,57,34,62,88,237,57,35,62,
-	0,237,57,36,237,57,37,33,128,2,125,237,
-	57,38,124,237,57,39,237,56,48,246,97,230,
-	207,237,57,48,62,0,237,57,0,62,0,211,
-	96,211,100,201,33,2,0,57,126,35,102,111,
-	237,56,48,230,175,237,57,48,62,12,237,57,
-	49,62,76,237,57,32,62,0,237,57,33,237,
-	57,34,125,237,57,35,124,237,57,36,62,0,
-	237,57,37,33,128,2,125,237,57,38,124,237,
-	57,39,237,56,48,246,97,230,207,237,57,48,
-	62,1,211,96,201,33,2,0,57,126,35,102,
-	111,229,237,56,48,230,87,237,57,48,125,237,
-	57,40,124,237,57,41,62,0,237,57,42,62,
-	67,237,57,43,62,0,237,57,44,58,106,137,
-	254,1,32,5,33,6,0,24,3,33,128,2,
-	125,237,57,46,124,237,57,47,237,56,50,230,
-	252,246,2,237,57,50,225,201,33,4,0,57,
-	94,35,86,33,2,0,57,126,35,102,111,237,
-	56,48,230,87,237,57,48,125,237,57,40,124,
-	237,57,41,62,0,237,57,42,62,67,237,57,
-	43,62,0,237,57,44,123,237,57,46,122,237,
-	57,47,237,56,50,230,244,246,0,237,57,50,
-	237,56,48,246,145,230,207,237,57,48,201,213,
-	237,56,46,95,237,56,47,87,237,56,46,111,
-	237,56,47,103,183,237,82,32,235,33,128,2,
-	183,237,82,209,201,213,237,56,38,95,237,56,
-	39,87,237,56,38,111,237,56,39,103,183,237,
-	82,32,235,33,128,2,183,237,82,209,201,245,
-	197,1,52,0,237,120,230,253,237,121,193,241,
-	201,245,197,1,52,0,237,120,246,2,237,121,
-	193,241,201,33,2,0,57,126,35,102,111,126,
-	35,110,103,201,33,0,0,34,102,152,34,96,
-	152,34,98,152,33,202,154,34,104,152,237,91,
-	104,152,42,226,149,183,237,82,17,0,255,25,
-	34,100,152,203,124,40,6,33,0,125,34,100,
-	152,42,104,152,35,35,35,229,205,120,139,193,
-	201,205,186,149,229,42,40,152,35,35,35,229,
-	205,39,144,193,124,230,3,103,221,117,254,221,
-	116,255,237,91,42,152,35,35,35,183,237,82,
-	32,12,17,5,0,42,42,152,205,171,149,242,
-	169,144,42,40,152,229,205,120,139,193,195,198,
-	149,237,91,42,152,42,98,152,25,34,98,152,
-	19,19,19,42,102,152,25,34,102,152,237,91,
-	100,152,33,158,253,25,237,91,102,152,205,171,
-	149,242,214,144,33,0,0,34,102,152,62,1,
-	50,95,152,205,225,144,195,198,149,58,95,152,
-	183,200,237,91,96,152,42,102,152,205,171,149,
-	242,5,145,237,91,102,152,33,98,2,25,237,
-	91,96,152,205,171,149,250,37,145,237,91,96,
-	152,42,102,152,183,237,82,32,7,42,98,152,
-	125,180,40,13,237,91,102,152,42,96,152,205,
-	171,149,242,58,145,237,91,104,152,42,102,152,
-	25,35,35,35,229,205,120,139,193,175,50,95,
-	152,201,195,107,139,205,206,149,250,255,243,205,
-	225,144,251,58,230,149,183,194,198,149,17,1,
-	0,42,98,152,205,171,149,250,198,149,62,1,
-	50,230,149,237,91,96,152,42,104,152,25,221,
-	117,252,221,116,253,237,91,104,152,42,96,152,
-	25,35,35,35,221,117,254,221,116,255,35,35,
-	35,229,205,39,144,124,230,3,103,35,35,35,
-	221,117,250,221,116,251,235,221,110,252,221,102,
-	253,115,35,114,35,54,4,62,1,211,100,211,
-	84,195,198,149,33,0,0,34,102,152,34,96,
-	152,34,98,152,33,202,154,34,104,152,237,91,
-	104,152,42,226,149,183,237,82,17,0,255,25,
-	34,100,152,33,109,152,54,0,33,107,152,229,
-	205,240,142,193,62,47,50,34,152,62,132,50,
-	49,152,205,241,145,205,61,145,58,39,152,60,
-	50,39,152,24,241,205,206,149,251,255,33,109,
-	152,126,183,202,198,149,110,221,117,251,33,109,
-	152,54,0,221,126,251,254,1,40,28,254,3,
-	40,101,254,4,202,190,147,254,5,202,147,147,
-	254,8,40,87,33,107,152,229,205,240,142,195,
-	198,149,58,201,154,183,32,21,33,111,152,126,
-	50,229,149,205,52,144,33,110,152,110,38,0,
-	229,205,11,142,193,237,91,96,152,42,104,152,
-	25,221,117,254,221,116,255,35,35,54,2,17,
-	2,0,43,43,115,35,114,58,44,152,35,35,
-	119,58,228,149,35,119,62,1,211,100,211,84,
-	62,1,50,201,154,24,169,205,153,142,58,231,
-	149,183,40,250,175,50,231,149,33,110,152,126,
-	254,255,40,91,58,233,149,230,63,183,40,83,
-	94,22,0,33,234,149,25,126,183,40,13,33,
-	110,152,94,33,234,150,25,126,254,3,32,36,
-	205,81,148,125,180,33,110,152,94,22,0,40,
-	17,33,234,149,25,54,0,33,107,152,229,205,
-	240,142,193,195,198,149,33,234,150,25,54,0,
-	33,110,152,94,22,0,33,234,149,25,126,50,
-	49,152,254,132,32,37,62,47,50,34,152,42,
-	107,152,229,33,110,152,229,205,174,140,193,193,
-	125,180,33,110,152,94,22,0,33,234,150,202,
-	117,147,25,52,195,120,147,58,49,152,254,140,
-	32,7,62,1,50,34,152,24,210,62,32,50,
-	106,152,24,19,58,49,152,95,58,106,152,163,
-	183,58,106,152,32,11,203,63,50,106,152,58,
-	106,152,183,32,231,254,2,40,51,254,4,40,
-	38,254,8,40,26,254,16,40,13,254,32,32,
-	158,62,165,50,49,152,62,69,24,190,62,164,
-	50,49,152,62,70,24,181,62,163,50,49,152,
-	175,24,173,62,162,50,49,152,62,1,24,164,
-	62,161,50,49,152,62,3,24,155,25,54,0,
-	221,126,251,254,8,40,7,58,230,149,183,202,
-	32,146,33,107,152,229,205,240,142,193,211,84,
-	195,198,149,237,91,96,152,42,104,152,25,221,
-	117,254,221,116,255,35,35,54,6,17,2,0,
-	43,43,115,35,114,58,228,149,35,35,119,58,
-	233,149,35,119,205,146,142,195,32,146,237,91,
-	96,152,42,104,152,25,229,205,160,142,193,58,
-	231,149,183,40,250,175,50,231,149,243,237,91,
-	96,152,42,104,152,25,221,117,254,221,116,255,
-	78,35,70,221,113,252,221,112,253,89,80,42,
-	98,152,183,237,82,34,98,152,203,124,40,19,
-	33,0,0,34,98,152,34,102,152,34,96,152,
-	62,1,50,95,152,24,40,221,94,252,221,86,
-	253,19,19,19,42,96,152,25,34,96,152,237,
-	91,100,152,33,158,253,25,237,91,96,152,205,
-	171,149,242,55,148,33,0,0,34,96,152,175,
-	50,230,149,251,195,32,146,245,62,1,50,231,
-	149,62,16,237,57,0,211,80,241,251,237,77,
-	201,205,186,149,229,229,33,0,0,34,37,152,
-	33,110,152,126,50,234,151,58,44,152,33,235,
-	151,119,221,54,253,0,221,54,254,0,195,230,
-	148,33,236,151,54,175,33,3,0,229,33,234,
-	151,229,205,174,140,193,193,33,236,151,126,254,
-	255,40,74,33,245,151,110,221,117,255,33,249,
-	151,126,221,166,255,221,119,255,33,253,151,126,
-	221,166,255,221,119,255,58,232,149,95,221,126,
-	255,163,221,119,255,183,40,15,230,191,33,110,
-	152,94,22,0,33,234,149,25,119,24,12,33,
-	110,152,94,22,0,33,234,149,25,54,132,33,
-	0,0,195,198,149,221,110,253,221,102,254,35,
-	221,117,253,221,116,254,17,32,0,221,110,253,
-	221,102,254,205,171,149,250,117,148,58,233,149,
-	203,87,40,84,33,1,0,34,37,152,221,54,
-	253,0,221,54,254,0,24,53,33,236,151,54,
-	175,33,3,0,229,33,234,151,229,205,174,140,
-	193,193,33,236,151,126,254,255,40,14,33,110,
-	152,94,22,0,33,234,149,25,54,140,24,159,
-	221,110,253,221,102,254,35,221,117,253,221,116,
-	254,17,32,0,221,110,253,221,102,254,205,171,
-	149,250,12,149,33,2,0,34,37,152,221,54,
-	253,0,221,54,254,0,24,54,33,236,151,54,
-	175,33,3,0,229,33,234,151,229,205,174,140,
-	193,193,33,236,151,126,254,255,40,15,33,110,
-	152,94,22,0,33,234,149,25,54,132,195,211,
-	148,221,110,253,221,102,254,35,221,117,253,221,
-	116,254,17,32,0,221,110,253,221,102,254,205,
-	171,149,250,96,149,33,1,0,195,198,149,124,
-	170,250,179,149,237,82,201,124,230,128,237,82,
-	60,201,225,253,229,221,229,221,33,0,0,221,
-	57,233,221,249,221,225,253,225,201,233,225,253,
-	229,221,229,221,33,0,0,221,57,94,35,86,
-	35,235,57,249,235,233,0,0,0,0,0,0,
-	62,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,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,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,
-	175,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,133,1,0,0,0,63,
-	255,255,255,255,0,0,0,63,0,0,0,0,
-	0,0,0,0,0,0,0,24,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
-	} ;
-
-#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops_ltdrv.h linux/drivers/net/cops_ltdrv.h
--- v2.3.49/linux/drivers/net/cops_ltdrv.h	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/cops_ltdrv.h	Wed Dec 31 16:00:00 1969
@@ -1,242 +0,0 @@
-/*
- *	The firmware this driver downloads into the Localtalk card is a
- *	separate program and is not GPL'd source code, even though the Linux
- *	side driver and the routine that loads this data into the card are.
- *	
- *	It is taken from the COPS SDK and is under the following license
- *
- *	This material is licensed to you strictly for use in conjunction with
- *	the use of COPS LocalTalk adapters.
- *	There is no charge for this SDK. And no waranty express or implied
- *	about its fitness for any purpose. However, we will cheerefully
- *	refund every penny you paid for this SDK...
- *	Regards,
- *
- *	Thomas F. Divine
- *	Chief Scientist
- */
-
-
-/*      cops_ltdrv.h: LocalTalk driver firmware dump for Linux.
- *
- *      Authors:
- *      - Jay Schulist <jschlst@turbolinux.com>
- */
- 
-#include <linux/config.h>
-
-#ifdef CONFIG_COPS_TANGENT
-
-unsigned char ltdrv_code[] = {
-	58,3,0,50,148,10,33,143,15,62,85,119,
-	190,32,9,62,170,119,190,32,3,35,24,241,
-	34,146,10,249,17,150,10,33,143,15,183,237,
-	82,77,68,11,107,98,19,54,0,237,176,62,
-	16,237,57,51,62,0,237,57,50,237,57,54,
-	62,12,237,57,49,62,195,33,39,2,50,56,
-	0,34,57,0,237,86,205,30,2,251,205,60,
-	10,24,169,67,111,112,121,114,105,103,104,116,
-	32,40,99,41,32,49,57,56,56,45,49,57,
-	57,50,44,32,80,114,105,110,116,105,110,103,
-	32,67,111,109,109,117,110,105,99,97,116,105,
-	111,110,115,32,65,115,115,111,99,105,97,116,
-	101,115,44,32,73,110,99,46,65,108,108,32,
-	114,105,103,104,116,115,32,114,101,115,101,114,
-	118,101,100,46,32,32,4,4,22,40,255,60,
-	4,96,10,224,6,0,7,126,2,64,11,246,
-	12,6,13,0,14,193,15,0,5,96,3,192,
-	1,0,9,8,62,3,211,82,62,192,211,82,
-	201,62,3,211,82,62,213,211,82,201,62,5,
-	211,82,62,224,211,82,201,62,5,211,82,62,
-	224,211,82,201,62,5,211,82,62,96,211,82,
-	201,6,28,33,180,1,14,82,237,163,194,4,
-	2,33,39,2,34,64,0,58,3,0,230,1,
-	192,62,11,237,121,62,118,237,121,201,33,182,
-	10,54,132,205,253,1,201,245,197,213,229,42,
-	150,10,14,83,17,98,2,67,20,237,162,58,
-	179,1,95,219,82,230,1,32,6,29,32,247,
-	195,17,3,62,1,211,82,219,82,95,230,160,
-	32,10,237,162,32,225,21,32,222,195,15,3,
-	237,162,123,230,96,194,21,3,62,48,211,82,
-	62,1,211,82,175,211,82,237,91,150,10,43,
-	55,237,82,218,19,3,34,152,10,98,107,58,
-	154,10,190,32,81,62,1,50,158,10,35,35,
-	62,132,190,32,44,54,133,43,70,58,154,10,
-	119,43,112,17,3,0,205,137,3,62,16,211,
-	82,62,56,211,82,205,217,1,42,150,10,14,
-	83,17,98,2,67,20,58,178,1,95,195,59,
-	2,62,129,190,194,227,2,54,130,43,70,58,
-	154,10,119,43,112,17,3,0,205,137,3,195,
-	254,2,35,35,126,254,132,194,227,2,205,61,
-	3,24,20,62,128,166,194,222,2,221,229,221,
-	33,175,10,205,93,6,205,144,7,221,225,225,
-	209,193,241,251,237,77,221,229,221,33,159,10,
-	205,93,6,221,225,205,61,3,195,247,2,24,
-	237,24,235,24,233,230,64,40,2,24,227,24,
-	225,175,50,179,10,205,208,1,201,197,33,4,
-	0,57,126,35,102,111,205,51,3,193,201,62,
-	1,50,179,10,34,150,10,54,0,58,179,10,
-	183,200,62,14,211,82,62,193,211,82,62,10,
-	211,82,62,224,211,82,62,6,211,82,58,154,
-	10,211,82,62,16,211,82,62,56,211,82,62,
-	48,211,82,219,82,230,1,40,4,219,83,24,
-	242,62,14,211,82,62,33,211,82,62,1,211,
-	82,62,9,211,82,62,32,211,82,205,217,1,
-	201,14,83,205,208,1,24,23,14,83,205,208,
-	1,205,226,1,58,174,1,61,32,253,205,244,
-	1,58,174,1,61,32,253,205,226,1,58,175,
-	1,61,32,253,62,5,211,82,62,233,211,82,
-	62,128,211,82,58,176,1,61,32,253,237,163,
-	27,62,192,211,82,219,82,230,4,40,250,237,
-	163,27,122,179,32,243,219,82,230,4,40,250,
-	58,178,1,71,219,82,230,4,40,3,5,32,
-	247,219,82,230,4,40,250,205,235,1,58,177,
-	1,61,32,253,205,244,1,201,229,213,35,35,
-	126,230,128,194,145,4,43,58,154,10,119,43,
-	70,33,181,10,119,43,112,17,3,0,243,62,
-	10,211,82,219,82,230,128,202,41,4,209,225,
-	62,1,55,251,201,205,144,3,58,180,10,254,
-	255,202,127,4,205,217,1,58,178,1,71,219,
-	82,230,1,32,6,5,32,247,195,173,4,219,
-	83,71,58,154,10,184,194,173,4,58,178,1,
-	71,219,82,230,1,32,6,5,32,247,195,173,
-	4,219,83,58,178,1,71,219,82,230,1,32,
-	6,5,32,247,195,173,4,219,83,254,133,194,
-	173,4,58,179,1,24,4,58,179,1,135,61,
-	32,253,209,225,205,137,3,205,61,3,183,251,
-	201,209,225,243,62,10,211,82,219,82,230,128,
-	202,164,4,62,1,55,251,201,205,144,3,205,
-	61,3,183,251,201,209,225,62,2,55,251,201,
-	243,62,14,211,82,62,33,211,82,251,201,33,
-	4,0,57,94,35,86,33,2,0,57,126,35,
-	102,111,221,229,34,193,10,237,83,195,10,221,
-	33,171,10,205,93,6,58,185,10,50,186,10,
-	58,184,10,135,50,184,10,205,112,6,254,3,
-	56,16,58,185,10,135,60,230,15,50,185,10,
-	175,50,184,10,24,23,58,183,10,205,112,6,
-	254,3,48,13,58,185,10,203,63,50,185,10,
-	62,255,50,183,10,58,185,10,50,186,10,58,
-	183,10,135,50,183,10,62,32,50,187,10,50,
-	188,10,6,255,219,82,230,16,32,3,5,32,
-	247,205,180,4,6,40,219,82,230,16,40,3,
-	5,32,247,62,10,211,82,219,82,230,128,194,
-	46,5,219,82,230,16,40,214,237,95,71,58,
-	186,10,160,230,15,40,32,71,14,10,62,10,
-	211,82,219,82,230,128,202,119,5,205,180,4,
-	195,156,5,219,82,230,16,202,156,5,13,32,
-	229,16,225,42,193,10,237,91,195,10,205,252,
-	3,48,7,61,202,156,5,195,197,5,221,225,
-	33,0,0,201,221,33,163,10,205,93,6,58,
-	188,10,61,50,188,10,40,19,58,186,10,246,
-	1,50,186,10,58,183,10,246,1,50,183,10,
-	195,46,5,221,225,33,1,0,201,221,33,167,
-	10,205,93,6,58,184,10,246,1,50,184,10,
-	58,186,10,135,246,1,50,186,10,58,187,10,
-	61,50,187,10,194,46,5,221,225,33,2,0,
-	201,221,229,33,0,0,57,17,4,0,25,126,
-	50,154,10,230,128,50,189,10,58,189,10,183,
-	40,6,221,33,88,2,24,4,221,33,150,0,
-	58,154,10,183,40,49,60,40,46,61,33,190,
-	10,119,35,119,35,54,129,175,50,158,10,221,
-	43,221,229,225,124,181,40,42,33,190,10,17,
-	3,0,205,206,4,17,232,3,27,123,178,32,
-	251,58,158,10,183,40,224,58,154,10,71,62,
-	7,128,230,127,71,58,189,10,176,50,154,10,
-	24,166,221,225,201,183,221,52,0,192,221,52,
-	1,192,221,52,2,192,221,52,3,192,55,201,
-	6,8,14,0,31,48,1,12,16,250,121,201,
-	33,2,0,57,94,35,86,35,78,35,70,35,
-	126,35,102,105,79,120,68,103,237,176,201,33,
-	2,0,57,126,35,102,111,62,17,237,57,48,
-	125,237,57,40,124,237,57,41,62,0,237,57,
-	42,62,64,237,57,43,62,0,237,57,44,33,
-	128,2,125,237,57,46,124,237,57,47,62,145,
-	237,57,48,211,68,58,149,10,211,66,201,33,
-	2,0,57,126,35,102,111,62,33,237,57,48,
-	62,64,237,57,32,62,0,237,57,33,237,57,
-	34,125,237,57,35,124,237,57,36,62,0,237,
-	57,37,33,128,2,125,237,57,38,124,237,57,
-	39,62,97,237,57,48,211,67,58,149,10,211,
-	66,201,237,56,46,95,237,56,47,87,237,56,
-	46,111,237,56,47,103,183,237,82,32,235,33,
-	128,2,183,237,82,201,237,56,38,95,237,56,
-	39,87,237,56,38,111,237,56,39,103,183,237,
-	82,32,235,33,128,2,183,237,82,201,205,106,
-	10,221,110,6,221,102,7,126,35,110,103,195,
-	118,10,205,106,10,33,0,0,34,205,10,34,
-	198,10,34,200,10,33,143,15,34,207,10,237,
-	91,207,10,42,146,10,183,237,82,17,0,255,
-	25,34,203,10,203,124,40,6,33,0,125,34,
-	203,10,42,207,10,229,205,37,3,195,118,10,
-	205,106,10,229,42,150,10,35,35,35,229,205,
-	70,7,193,124,230,3,103,221,117,254,221,116,
-	255,237,91,152,10,35,35,35,183,237,82,32,
-	12,17,5,0,42,152,10,205,91,10,242,203,
-	7,42,150,10,229,205,37,3,195,118,10,237,
-	91,152,10,42,200,10,25,34,200,10,42,205,
-	10,25,34,205,10,237,91,203,10,33,158,253,
-	25,237,91,205,10,205,91,10,242,245,7,33,
-	0,0,34,205,10,62,1,50,197,10,205,5,
-	8,33,0,0,57,249,195,118,10,205,106,10,
-	58,197,10,183,202,118,10,237,91,198,10,42,
-	205,10,205,91,10,242,46,8,237,91,205,10,
-	33,98,2,25,237,91,198,10,205,91,10,250,
-	78,8,237,91,198,10,42,205,10,183,237,82,
-	32,7,42,200,10,125,180,40,13,237,91,205,
-	10,42,198,10,205,91,10,242,97,8,237,91,
-	207,10,42,205,10,25,229,205,37,3,175,50,
-	197,10,195,118,10,205,29,3,33,0,0,57,
-	249,195,118,10,205,106,10,58,202,10,183,40,
-	22,205,14,7,237,91,209,10,19,19,19,205,
-	91,10,242,139,8,33,1,0,195,118,10,33,
-	0,0,195,118,10,205,126,10,252,255,205,108,
-	8,125,180,194,118,10,237,91,200,10,33,0,
-	0,205,91,10,242,118,10,237,91,207,10,42,
-	198,10,25,221,117,254,221,116,255,35,35,35,
-	229,205,70,7,193,124,230,3,103,35,35,35,
-	221,117,252,221,116,253,229,221,110,254,221,102,
-	255,229,33,212,10,229,205,124,6,193,193,221,
-	110,252,221,102,253,34,209,10,33,211,10,54,
-	4,33,209,10,227,205,147,6,193,62,1,50,
-	202,10,243,221,94,252,221,86,253,42,200,10,
-	183,237,82,34,200,10,203,124,40,17,33,0,
-	0,34,200,10,34,205,10,34,198,10,50,197,
-	10,24,37,221,94,252,221,86,253,42,198,10,
-	25,34,198,10,237,91,203,10,33,158,253,25,
-	237,91,198,10,205,91,10,242,68,9,33,0,
-	0,34,198,10,205,5,8,33,0,0,57,249,
-	251,195,118,10,205,106,10,33,49,13,126,183,
-	40,16,205,42,7,237,91,47,13,19,19,19,
-	205,91,10,242,117,9,58,142,15,198,1,50,
-	142,15,195,118,10,33,49,13,126,254,1,40,
-	25,254,3,202,7,10,254,5,202,21,10,33,
-	49,13,54,0,33,47,13,229,205,207,6,195,
-	118,10,58,141,15,183,32,72,33,51,13,126,
-	50,149,10,205,86,7,33,50,13,126,230,127,
-	183,32,40,58,142,15,230,127,50,142,15,183,
-	32,5,198,1,50,142,15,33,50,13,126,111,
-	23,159,103,203,125,58,142,15,40,5,198,128,
-	50,142,15,33,50,13,119,33,50,13,126,111,
-	23,159,103,229,205,237,5,193,33,211,10,54,
-	2,33,2,0,34,209,10,58,154,10,33,212,
-	10,119,58,148,10,33,213,10,119,33,209,10,
-	229,205,147,6,193,24,128,42,47,13,229,33,
-	50,13,229,205,191,4,193,24,239,33,211,10,
-	54,6,33,3,0,34,209,10,58,154,10,33,
-	212,10,119,58,148,10,33,213,10,119,33,214,
-	10,54,5,33,209,10,229,205,147,6,24,200,
-	205,106,10,33,49,13,54,0,33,47,13,229,
-	205,207,6,33,209,10,227,205,147,6,193,205,
-	80,9,205,145,8,24,248,124,170,250,99,10,
-	237,82,201,124,230,128,237,82,60,201,225,253,
-	229,221,229,221,33,0,0,221,57,233,221,249,
-	221,225,253,225,201,233,225,253,229,221,229,221,
-	33,0,0,221,57,94,35,86,35,235,57,249,
-	235,233,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
-	} ;
-
-#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.3.49/linux/drivers/net/cs89x0.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/cs89x0.c	Fri Mar  3 12:56:13 2000
@@ -1,4 +1,7 @@
-/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
+/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0
+ *  driver for linux.
+ */
+
 /*
 	Written 1996 by Russell Nelson, with reference to skeleton.c
 	written 1993-1994 by Donald Becker.
@@ -6,8 +9,8 @@
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
-	The author may be reached at nelson@crynwr.com, Crynwr
-	Software, 11 Grant St., Potsdam, NY 13676
+        The author may be reached at nelson@crynwr.com, Crynwr
+        Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
 
   Changelog:
 
@@ -25,19 +28,30 @@
                     : as an example. Disabled autoprobing in init_module(),
                     : not a good thing to do to other devices while Linux
                     : is running from all accounts.
-                    
+
+  Russ Nelson       : Jul 13 1998.  Added RxOnly DMA support.
+
+  Melody Lee        : Aug 10 1999.  Changes for Linux 2.2.5 compatibility. 
+                    : email: ethernet@crystal.cirrus.com
+
   Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
+
+  Andrew Morton     : andrewm@uow.edu.au
+                    : Kernel 2.3.48
+                    : Handle kmalloc() failures
+                    : Other resource allocation fixes
+                    : Add SMP locks
+                    : Integrate Russ Nelson's ALLOW_DMA functionality back in.
+                    : If ALLOW_DMA is true, make DMA runtime selectable
+                    : Folded in changes from Cirrus (Melody Lee
+                    : <klee@crystal.cirrus.com>)
+                    : Don't call netif_wake_queue() in net_send_packet()
+                    : Fixed an out-of-mem bug in dma_rx()
+                    : Updated Documentation/cs89x0.txt
 */
 
 static char *version =
-"cs89x0.c:v1.03 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
-
-/* ======================= configure the driver here ======================= */
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 2
-#endif
+"cs89x0.c: (kernel 2.3.48) Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
 
 /* ======================= end of configuration ======================= */
 
@@ -52,7 +66,19 @@
 #define MOD_DEC_USE_COUNT
 #endif
 
-#define PRINTK(x) printk x
+/*
+ * Set this to zero to disable DMA code
+ *
+ * Note that even if DMA is turned off we still support the 'dma' and  'use_dma'
+ * module options so we don't break any startup scripts.
+ */
+#define ALLOW_DMA	1
+
+/*
+ * Set this to zero to remove all the debug statements via
+ * dead code elimination
+ */
+#define DEBUGGING	0
 
 /*
   Sources:
@@ -76,39 +102,66 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#if ALLOW_DMA
+#include <asm/dma.h>
+#endif
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+
 #include "cs89x0.h"
 
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int netcard_portlist[] __initdata =
-   { 0x300, 0x320, 0x340, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+   { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 
-static unsigned int net_debug = NET_DEBUG;
+#if DEBUGGING
+static unsigned int net_debug = 5;
+#else
+#define net_debug 0	/* gcc will remove all the debug code for us */
+#endif
 
 /* The number of low I/O ports used by the ethercard. */
 #define NETCARD_IO_EXTENT	16
 
+/* we allow the user to override various values normally set in the EEPROM */
+#define FORCE_RJ45	0x0001    /* pick one of these three */
+#define FORCE_AUI	0x0002
+#define FORCE_BNC	0x0004
+
+#define FORCE_AUTO	0x0010    /* pick one of these three */
+#define FORCE_HALF	0x0020
+#define FORCE_FULL	0x0030
+
 /* Information that need to be kept for each board. */
 struct net_local {
 	struct net_device_stats stats;
 	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
 	char chip_revision;	/* revision letter of the chip ('A'...) */
-	int send_cmd;		/* the propercommand used to send a packet. */
-	int auto_neg_cnf;
-	int adapter_cnf;
-	int isa_config;
-	int irq_map;
-	int rx_mode;
-	int curr_rx_cfg;
-        int linectl;
-        int send_underrun;      /* keep track of how many underruns in a row we get */
-	struct sk_buff *skb;
+	int send_cmd;		/* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */
+	int auto_neg_cnf;	/* auto-negotiation word from EEPROM */
+	int adapter_cnf;	/* adapter configuration from EEPROM */
+	int isa_config;		/* ISA configuration from EEPROM */
+	int irq_map;		/* IRQ map from EEPROM */
+	int rx_mode;		/* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */
+	int curr_rx_cfg;	/* a copy of PP_RxCFG */
+	int linectl;		/* either 0 or LOW_RX_SQUELCH, depending on configuration. */
+	int send_underrun;	/* keep track of how many underruns in a row we get */
+	int force;		/* force various values; see FORCE* above. */
+	spinlock_t lock;
+#if ALLOW_DMA
+	int use_dma;		/* Flag: we're using dma */
+	int dma;		/* DMA channel */
+	int dmasize;		/* 16 or 64 */
+	unsigned char *dma_buff;	/* points to the beginning of the buffer */
+	unsigned char *end_dma_buff;	/* points to the end of the buffer */
+	unsigned char *rx_dma_ptr;	/* points to the next packet  */
+#endif
 };
 
 /* Index to functions, as function prototypes. */
@@ -117,7 +170,7 @@
 
 static int cs89x0_probe1(struct net_device *dev, int ioaddr);
 static int net_open(struct net_device *dev);
-static int	net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void set_multicast_list(struct net_device *dev);
 static void net_timeout(struct net_device *dev);
@@ -128,7 +181,11 @@
 static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer);
 static int get_eeprom_cksum(int off, int len, int *buffer);
 static int set_mac_address(struct net_device *dev, void *addr);
-
+static void count_rx_errors(int status, struct net_local *lp);
+#if ALLOW_DMA
+static void get_dma_channel(struct net_device *dev);
+static void release_dma_buff(struct net_local *lp);
+#endif
 
 /* Example routines you must write ;->. */
 #define tx_done(dev) 1
@@ -139,6 +196,7 @@
    If dev->base_addr == 1, always return failure.
    If dev->base_addr == 2, allocate space for the device and return success
    (detachable devices only).
+   Return 0 on success.
    */
 
 int __init cs89x0_probe(struct net_device *dev)
@@ -146,6 +204,9 @@
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
 
+	if (net_debug)
+		printk("cs89x0:cs89x0_probe()\n");
+
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return cs89x0_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
@@ -158,34 +219,38 @@
 		if (cs89x0_probe1(dev, ioaddr) == 0)
 			return 0;
 	}
-	printk("cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
+	printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
 	return ENODEV;
 }
 
-extern int inline readreg(struct net_device *dev, int portno)
+extern int inline
+readreg(struct net_device *dev, int portno)
 {
 	outw(portno, dev->base_addr + ADD_PORT);
 	return inw(dev->base_addr + DATA_PORT);
 }
 
-extern  void inline writereg(struct net_device *dev, int portno, int value)
+extern void inline
+writereg(struct net_device *dev, int portno, int value)
 {
 	outw(portno, dev->base_addr + ADD_PORT);
 	outw(value, dev->base_addr + DATA_PORT);
 }
 
-
-extern int inline readword(struct net_device *dev, int portno)
+extern int inline
+readword(struct net_device *dev, int portno)
 {
 	return inw(dev->base_addr + portno);
 }
 
-extern void inline writeword(struct net_device *dev, int portno, int value)
+extern void inline
+writeword(struct net_device *dev, int portno, int value)
 {
 	outw(value, dev->base_addr + portno);
 }
 
-static int __init wait_eeprom_ready(struct net_device *dev)
+static int __init
+wait_eeprom_ready(struct net_device *dev)
 {
 	int timeout = jiffies;
 	/* check to see if the EEPROM is ready, a timeout is used -
@@ -197,7 +262,8 @@
 	return 0;
 }
 
-static int __init get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
+static int __init
+get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
 {
 	int i;
 
@@ -214,7 +280,8 @@
         return 0;
 }
 
-static int  __init  get_eeprom_cksum(int off, int len, int *buffer)
+static int  __init
+get_eeprom_cksum(int off, int len, int *buffer)
 {
 	int i, cksum;
 
@@ -229,19 +296,28 @@
 
 /* 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.  */
+   verifies that the correct device exists and functions.
+   Return 0 on success.
+ */
 
-static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
+static int __init
+cs89x0_probe1(struct net_device *dev, int ioaddr)
 {
 	struct net_local *lp;
 	static unsigned version_printed = 0;
 	int i;
 	unsigned rev_type = 0;
 	int eeprom_buff[CHKSUM_LEN];
+	int retval;
 
 	/* Initialize the device structure. */
 	if (dev->priv == NULL) {
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+		if (dev->priv == 0)
+		{
+			retval = ENOMEM;
+			goto out;
+		}
                 memset(dev->priv, 0, sizeof(struct net_local));
         }
 	lp = (struct net_local *)dev->priv;
@@ -257,7 +333,10 @@
 	}
 
 	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
-		return ENODEV;
+	{
+		retval = ENODEV;
+		goto out1;
+	}
 
 	/* Fill in the 'dev' fields. */
 	dev->base_addr = ioaddr;
@@ -278,7 +357,7 @@
 	if (net_debug  &&  version_printed++ == 0)
 		printk(version);
 
-	printk("%s: cs89%c0%s rev %c found at %#3lx",
+	printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ",
 	       dev->name,
 	       lp->chip_type==CS8900?'0':'2',
 	       lp->chip_type==CS8920M?"M":"",
@@ -289,11 +368,11 @@
 
 	/* First check to see if an EEPROM is attached*/
 	if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
-		printk("\ncs89x0: No EEPROM, relying on command line....\n");
+		printk(KERN_WARNING "\ncs89x0: No EEPROM, relying on command line....\n");
 	else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
-		printk("\ncs89x0: EEPROM read failed, relying on command line.\n");
+		printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n");
         } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
-                printk("\ncs89x0: EEPROM checksum bad, relying on command line\n");
+                printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying on command line\n");
         } else {
                 /* get transmission control word  but keep the autonegotiation bits */
                 if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
@@ -301,16 +380,36 @@
                 if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
                 /* Store ISA configuration */
                 lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2];
-                /* store the initial memory base address */
                 dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
+
+                /* eeprom_buff has 32-bit ints, so we can't just memcpy it */
+                /* store the initial memory base address */
                 for (i = 0; i < ETH_ALEN/2; i++) {
                         dev->dev_addr[i*2] = eeprom_buff[i];
                         dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
                 }
         }
 
+        /* allow them to force multiple transceivers.  If they force multiple, autosense */
+        {
+		int count = 0;
+		if (lp->force & FORCE_RJ45)	{lp->adapter_cnf |= A_CNF_10B_T; count++; }
+		if (lp->force & FORCE_AUI) 	{lp->adapter_cnf |= A_CNF_AUI; count++; }
+		if (lp->force & FORCE_BNC)	{lp->adapter_cnf |= A_CNF_10B_2; count++; }
+		if (count > 1)			{lp->adapter_cnf |= A_CNF_MEDIA_AUTO; }
+		else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; }
+		else if (lp->force & FORCE_AUI)	{lp->adapter_cnf |= A_CNF_MEDIA_AUI; }
+		else if (lp->force & FORCE_BNC)	{lp->adapter_cnf |= A_CNF_MEDIA_10B_2; }
+        }
+
+        /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
+
+        /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
 
-	printk(" media %s%s%s",
+        /* FIXME: we don't set the Ethernet address on the command line.  Use
+           ifconfig IFACE hw ether AABBCCDDEEFF */
+
+	printk(KERN_INFO "cs89x0 media %s%s%s",
 	       (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"",
 	       (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"",
 	       (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":"");
@@ -353,14 +452,33 @@
 			dev->irq = i;
 	}
 
-	printk(" IRQ %d", dev->irq);
+	printk(", IRQ %d", dev->irq);
 
+#if ALLOW_DMA
+	if (lp->use_dma)
+	{
+		get_dma_channel(dev);
+		printk(", DMA %d", dev->dma);
+	}
+	else
+#endif
+	{
+		printk(", programmed I/O");
+	}
 
 	/* print the ethernet address. */
+	printk(", MAC ");
 	for (i = 0; i < ETH_ALEN; i++)
-		printk(" %2.2x", dev->dev_addr[i]);
+	{
+		printk("%s%02x", i ? ":" : "", dev->dev_addr[i]);
+	}
 
 	/* Grab the region so we can find another board if autoIRQ fails. */
+
+	/*
+	 * FIXME: we should check this, but really the isapnp stuff should have given
+	 * us a free region.  Sort this out when the isapnp is sorted out
+	 */
 	request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0");
 
 	dev->open		= net_open;
@@ -376,11 +494,188 @@
 	ether_setup(dev);
 
 	printk("\n");
+	if (net_debug)
+		printk("cs89x0_probe1() successful\n");
 	return 0;
+out1:
+	kfree(dev->priv);
+	dev->priv = 0;
+out:
+	return retval;
+}
+
+
+/*********************************
+ * This page contains DMA routines
+**********************************/
+
+#if ALLOW_DMA
+
+#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
+
+static void
+get_dma_channel(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (lp->dma) {
+		dev->dma = lp->dma;
+		lp->isa_config |= ISA_RxDMA;
+	} else {
+		if ((lp->isa_config & ANY_ISA_DMA) == 0)
+			return;
+		dev->dma = lp->isa_config & DMA_NO_MASK;
+		if (lp->chip_type == CS8900)
+			dev->dma += 5;
+		if (dev->dma < 5 || dev->dma > 7) {
+			lp->isa_config &= ~ANY_ISA_DMA;
+			return;
+		}
+	}
+	return;
+}
+
+static void
+write_dma(struct net_device *dev, int chip_type, int dma)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	if ((lp->isa_config & ANY_ISA_DMA) == 0)
+		return;
+	if (chip_type == CS8900) {
+		writereg(dev, PP_CS8900_ISADMA, dma-5);
+	} else {
+		writereg(dev, PP_CS8920_ISADMA, dma);
+	}
+}
+
+static void
+set_dma_cfg(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (lp->use_dma)
+	{
+		if ((lp->isa_config & ANY_ISA_DMA) == 0)
+		{
+			if (net_debug > 3)
+				printk("set_dma_cfg(): no DMA\n");
+			return;
+		}
+		if (lp->isa_config & ISA_RxDMA)
+		{
+			lp->curr_rx_cfg |= RX_DMA_ONLY;
+			if (net_debug > 3)
+				printk("set_dma_cfg(): RX_DMA_ONLY\n");
+		}
+		else
+		{
+			lp->curr_rx_cfg |= AUTO_RX_DMA;	/* not that we support it... */
+			if (net_debug > 3)
+				printk("set_dma_cfg(): AUTO_RX_DMA\n");
+		}
+	}
+}
+
+static int
+dma_bufcfg(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	if (lp->use_dma)
+		return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0;
+	else
+		return 0;
+}
+
+static int
+dma_busctl(struct net_device *dev)
+{
+	int retval = 0;
+	struct net_local *lp = (struct net_local *)dev->priv;
+	if (lp->use_dma)
+	{
+		if (lp->isa_config & ANY_ISA_DMA)
+			retval |= RESET_RX_DMA; /* Reset the DMA pointer */
+		if (lp->isa_config & DMA_BURST)
+			retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */
+		if (lp->dmasize == 64)
+			retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */
+		retval |= MEMORY_ON;	/* we need memory enabled to use DMA. */
+	}
+	return retval;
+}
+
+static void
+dma_rx(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	struct sk_buff *skb;
+	int status, length;
+	unsigned char *bp = lp->rx_dma_ptr;
+
+	{
+		int i;
+		for (i = 0; i < 1000; i++)
+			;
+	}
+
+	status = bp[0] + (bp[1]<<8);
+	length = bp[2] + (bp[3]<<8);
+	bp += 4;
+	if (net_debug > 5)
+	{
+		printk(	"%s: receiving DMA packet at %lx, status %x, length %x\n",
+			dev->name, (unsigned long)bp, status, length);
+	}
+	if ((status & RX_OK) == 0) {
+		count_rx_errors(status, lp);
+		goto skip_this_frame;
+	}
+
+	/* Malloc up new buffer. */
+	skb = alloc_skb(length, GFP_ATOMIC);
+	if (skb == NULL) {
+		if (net_debug)	/* I don't think we want to do this to a stressed system */
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+		lp->stats.rx_dropped++;
+
+		/* AKPM: advance bp to the next frame */
+skip_this_frame:
+		bp += (length + 3) & ~3;
+		if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024;
+		lp->rx_dma_ptr = bp;
+		return;
+	}
+
+	skb->len = length;
+	skb->dev = dev;
+
+	if (bp + length > lp->end_dma_buff) {
+		int semi_cnt = lp->end_dma_buff - bp;
+		memcpy(skb_put(skb,semi_cnt), bp, semi_cnt);
+		memcpy(skb_put(skb,length - semi_cnt), lp->dma_buff,
+		       length - semi_cnt);
+	} else {
+		memcpy(skb_put(skb,length), bp, length);
+	}
+	bp += (length + 3) & ~3;
+	if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024;
+	lp->rx_dma_ptr = bp;
+
+	if (net_debug > 3)
+	{
+		printk(	"%s: received %d byte DMA packet of type %x\n",
+			dev->name, length,
+			(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+	}
+        skb->protocol=eth_type_trans(skb,dev);
+	netif_rx(skb);
+	lp->stats.rx_packets++;
+	return;
 }
 
-void  __init 
-reset_chip(struct net_device *dev)
+#endif	/* ALLOW_DMA */
+
+void  __init reset_chip(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
@@ -399,8 +694,8 @@
 		outb(0,      ioaddr + DATA_PORT + 1);
 
 		outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT);
-		outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT);
-		outb((dev->mem_start >> 24) & 0xff,   ioaddr + DATA_PORT + 1);
+		outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT);
+		outb((dev->mem_start >> 8) & 0xff,   ioaddr + DATA_PORT + 1);
 	}
 	/* Wait until the chip is reset */
 	reset_start_time = jiffies;
@@ -430,11 +725,18 @@
 
 }
 
+#define DETECTED_NONE  0
+#define DETECTED_RJ45H 1
+#define DETECTED_RJ45F 2
+#define DETECTED_AUI   3
+#define DETECTED_BNC   4
+
 static int
 detect_tp(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int timenow = jiffies;
+	int fdx;
 
 	if (net_debug > 1) printk("%s: Attempting TP\n", dev->name);
 
@@ -450,35 +752,63 @@
 	for (timenow = jiffies; jiffies - timenow < 15; )
                 ;
 	if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
-		return 0;
+		return DETECTED_NONE;
 
-	if (lp->chip_type != CS8900) {
+	if (lp->chip_type == CS8900) {
+                switch (lp->force & 0xf0) {
+#if 0
+                case FORCE_AUTO:
+			printk("%s: cs8900 doesn't autonegotiate\n",dev->name);
+                        return DETECTED_NONE;
+#endif
+		/* CS8900 doesn't support AUTO, change to HALF*/
+                case FORCE_AUTO:
+			lp->force &= ~FORCE_AUTO;
+                        lp->force |= FORCE_HALF;
+			break;
+		case FORCE_HALF:
+			break;
+                case FORCE_FULL:
+			writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900);
+			break;
+                }
+		fdx = readreg(dev, PP_TestCTL) & FDX_8900;
+	} else {
+		switch (lp->force & 0xf0) {
+		case FORCE_AUTO:
+			lp->auto_neg_cnf = AUTO_NEG_ENABLE;
+			break;
+		case FORCE_HALF:
+			lp->auto_neg_cnf = 0;
+			break;
+		case FORCE_FULL:
+			lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX;
+			break;
+                }
 
 		writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);
 
 		if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
-			printk("%s: negotiating duplex...\n",dev->name);
+			printk(KERN_INFO "%s: negotiating duplex...\n",dev->name);
 			while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
 				if (jiffies - timenow > 4000) {
-					printk("**** Full / half duplex auto-negotiation timed out ****\n");
+					printk(KERN_ERR "**** Full / half duplex auto-negotiation timed out ****\n");
 					break;
 				}
 			}
 		}
-		if (readreg(dev, PP_AutoNegST) & FDX_ACTIVE)
-			printk("%s: using full duplex\n", dev->name);
-		else
-			printk("%s: using half duplex\n", dev->name);
+		fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE;
 	}
-
-	return A_CNF_MEDIA_10B_T;
+	if (fdx)
+		return DETECTED_RJ45F;
+	else
+		return DETECTED_RJ45H;
 }
 
 /* send a test packet - return true if carrier bits are ok */
 static int
 send_test_pkt(struct net_device *dev)
 {
-	int ioaddr = dev->base_addr;
 	char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
 				 0, 46, /* A 46 in network order */
 				 0, 0, /* DSAP=0 & SSAP=0 fields */
@@ -490,8 +820,8 @@
 	memcpy(test_packet,          dev->dev_addr, ETH_ALEN);
 	memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN);
 
-        outw(TX_AFTER_ALL, ioaddr + TX_CMD_PORT);
-        outw(ETH_ZLEN, ioaddr + TX_LEN_PORT);
+        writeword(dev, TX_CMD_PORT, TX_AFTER_ALL);
+        writeword(dev, TX_LEN_PORT, ETH_ZLEN);
 
 	/* Test to see if the chip has allocated memory for the packet */
 	while (jiffies - timenow < 5)
@@ -501,11 +831,7 @@
 		return 0;	/* this shouldn't happen */
 
 	/* Write the contents of the packet */
-	if (dev->mem_start) {
-		memcpy((void *)dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN);
-	} else {
-		outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
-	}
+	outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);
 
 	if (net_debug > 1) printk("Sending test packet ");
 	/* wait a couple of jiffies for packet to be received */
@@ -531,9 +857,9 @@
 	writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
 
 	if (send_test_pkt(dev))
-		return A_CNF_MEDIA_AUI;
+		return DETECTED_AUI;
 	else
-		return 0;
+		return DETECTED_NONE;
 }
 
 static int
@@ -547,9 +873,9 @@
 	writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);
 
 	if (send_test_pkt(dev))
-		return A_CNF_MEDIA_10B_2;
+		return DETECTED_BNC;
 	else
-		return 0;
+		return DETECTED_NONE;
 }
 
 
@@ -579,6 +905,9 @@
    registers that "should" only need to be set once at boot, so that
    there is non-reboot way to recover if something goes wrong.
    */
+
+/* AKPM: do we need to do any locking here? */
+
 static int
 net_open(struct net_device *dev)
 {
@@ -588,9 +917,15 @@
 
 	if (dev->irq < 2) {
 		/* Allow interrupts to be generated by the chip */
+/* Cirrus' release had this: */
+#if 0
+		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
+#endif
+/* And 2.3.47 had this: */
 		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+
 		for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {
-			if (request_irq (i, NULL, 0, "cs8920", dev) != -EBUSY) {
+			if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) {
 				write_irq(dev, lp->chip_type, i);
 				writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
 				if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0)
@@ -601,21 +936,74 @@
 
 		if (i >= CS8920_NO_INTS) {
 			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */
+			if (net_debug)
+				printk("cs89x0: can't get an interrupt\n");
 			return -EAGAIN;
 		}
 	} else {
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
-			printk("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
+			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
 			return -EAGAIN;
 		}
+/* FIXME: Cirrus' release had this: */
+		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
+/* And 2.3.47 had this: */
+#if 0
 		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
+#endif
 		write_irq(dev, lp->chip_type, dev->irq);
 		if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) {
+			if (net_debug)
+				printk("cs89x0: request_irq(%d) failed\n", dev->irq);
 			return -EAGAIN;
 		}
 	}
 
+#if ALLOW_DMA
+	if (lp->use_dma)
+	{
+		if (lp->isa_config & ANY_ISA_DMA) {
+			unsigned long flags;
+			lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
+							(lp->dmasize * 1024) / PAGE_SIZE);
+
+			if (!lp->dma_buff) {
+				printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize);
+				goto release_irq;
+			}
+			if (net_debug > 1)
+			{
+				printk(	"%s: dma %lx %lx\n",
+					dev->name,
+					(unsigned long)lp->dma_buff,
+					(unsigned long)virt_to_bus(lp->dma_buff));
+			}
+			if ((unsigned long)virt_to_bus(lp->dma_buff) >= MAX_DMA_ADDRESS ||
+			    !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) {
+				printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name);
+				goto release_irq;
+			}
+			memset(lp->dma_buff, 0, lp->dmasize * 1024);	/* Why? */
+			if (request_dma(dev->dma, "cs89x0")) {
+				printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);
+				goto release_irq;
+			}
+			write_dma(dev, lp->chip_type, dev->dma);
+			lp->rx_dma_ptr = lp->dma_buff;
+			lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024;
+			spin_lock_irqsave(&lp->lock, flags);
+			disable_dma(dev->dma);
+			clear_dma_ff(dev->dma);
+			set_dma_mode(dev->dma, 0x14); /* auto_init as well */
+			set_dma_addr(dev->dma, virt_to_bus(lp->dma_buff));
+			set_dma_count(dev->dma, lp->dmasize*1024);
+			enable_dma(dev->dma);
+			spin_unlock_irqrestore(&lp->lock, flags);
+		}
+	}
+#endif	/* ALLOW_DMA */
+
 	/* set the Ethernet address */
 	for (i=0; i < ETH_ALEN/2; i++)
 		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
@@ -637,8 +1025,11 @@
         default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
         }
         if (!result) {
-                printk("%s: EEPROM is configured for unavailable media\n", dev->name);
+                printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
+#if ALLOW_DMA
+		release_dma_buff(lp);
+#endif
                 writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
                 free_irq(dev->irq, dev);
 		return -EAGAIN;
@@ -648,43 +1039,58 @@
 	switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
 	case A_CNF_MEDIA_10B_T:
                 result = detect_tp(dev);
-                if (!result) printk("%s: 10Base-T (RJ-45) has no cable\n", dev->name);
-                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-                        result = A_CNF_MEDIA_10B_T; /* Yes! I don't care if I see a link pulse */
+                if (result==DETECTED_NONE) {
+                        printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name);
+                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                                result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */
+                }
 		break;
 	case A_CNF_MEDIA_AUI:
                 result = detect_aui(dev);
-                if (!result) printk("%s: 10Base-5 (AUI) has no cable\n", dev->name);
-                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-                        result = A_CNF_MEDIA_AUI; /* Yes! I don't care if I see a carrrier */
+                if (result==DETECTED_NONE) {
+                        printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name);
+                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                                result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */
+                }
 		break;
 	case A_CNF_MEDIA_10B_2:
                 result = detect_bnc(dev);
-                if (!result) printk("%s: 10Base-2 (BNC) has no cable\n", dev->name);
-                if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-                        result = A_CNF_MEDIA_10B_2; /* Yes! I don't care if I can xmit a packet */
+                if (result==DETECTED_NONE) {
+                        printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name);
+                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
+                                result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */
+                }
 		break;
 	case A_CNF_MEDIA_AUTO:
 		writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);
 		if (lp->adapter_cnf & A_CNF_10B_T)
-			if ((result = detect_tp(dev)) != 0)
+			if ((result = detect_tp(dev)) != DETECTED_NONE)
 				break;
 		if (lp->adapter_cnf & A_CNF_AUI)
-			if ((result = detect_aui(dev)) != 0)
+			if ((result = detect_aui(dev)) != DETECTED_NONE)
 				break;
 		if (lp->adapter_cnf & A_CNF_10B_2)
-			if ((result = detect_bnc(dev)) != 0)
+			if ((result = detect_bnc(dev)) != DETECTED_NONE)
 				break;
-		printk("%s: no media detected\n", dev->name);
+		printk(KERN_ERR "%s: no media detected\n", dev->name);
                 goto release_irq;
 	}
 	switch(result) {
-	case 0: printk("%s: no network cable attached to configured media\n", dev->name);
+	case DETECTED_NONE:
+		printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name);
                 goto release_irq;
-	case A_CNF_MEDIA_10B_T: printk("%s: using 10Base-T (RJ-45)\n", dev->name);break;
-	case A_CNF_MEDIA_AUI:   printk("%s: using 10Base-5 (AUI)\n", dev->name);break;
-	case A_CNF_MEDIA_10B_2: printk("%s: using 10Base-2 (BNC)\n", dev->name);break;
-	default: printk("%s: unexpected result was %x\n", dev->name, result); goto release_irq;
+	case DETECTED_RJ45H:
+		printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
+		break;
+	case DETECTED_RJ45F:
+		printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);
+		break;
+	case DETECTED_AUI:
+		printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name);
+		break;
+	case DETECTED_BNC:
+		printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name);
+		break;
 	}
 
 	/* Turn on both receive and transmit operations */
@@ -695,22 +1101,34 @@
 	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
 
 	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
+
 	if (lp->isa_config & STREAM_TRANSFER)
 		lp->curr_rx_cfg |= RX_STREAM_ENBL;
-
+#if ALLOW_DMA
+	set_dma_cfg(dev);
+#endif
 	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
 
 	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
-	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
+		TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
 
 	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
-		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
+#if ALLOW_DMA
+		dma_bufcfg(dev) |
+#endif
+		TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
 
 	/* now that we've got our act together, enable everything */
 	writereg(dev, PP_BusCTL, ENABLE_IRQ
+		 | (dev->mem_start?MEMORY_ON : 0) /* turn memory on */
+#if ALLOW_DMA
+		 | dma_busctl(dev)
+#endif
                  );
         MOD_INC_USE_COUNT;
         netif_start_queue(dev);
+	if (net_debug)
+		printk("cs89x0: net_open() succeeded\n");
 	return 0;
 }
 
@@ -727,39 +1145,54 @@
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	short ioaddr = dev->base_addr;
-	unsigned long flags;
 
 	if (net_debug > 3)
-		printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+	{
+		printk("%s: sent %d byte packet of type %x\n",
+			dev->name, skb->len,
+			(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+	}
 
 	/* keep the upload from being interrupted, since we
                   ask the chip to start transmitting before the
                   whole packet has been completely uploaded. */
 
-	save_flags(flags);
-	cli();
+	spin_lock_irq(&lp->lock);
 	netif_stop_queue(dev);
-	
+
 	/* initiate a transmit sequence */
-	outw(lp->send_cmd, ioaddr + TX_CMD_PORT);
-	outw(skb->len, ioaddr + TX_LEN_PORT);
+	writeword(dev, TX_CMD_PORT, lp->send_cmd);
+	writeword(dev, TX_LEN_PORT, skb->len);
 
 	/* Test to see if the chip has allocated memory for the packet */
-	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
-		/* Gasp!  It hasn't.  But that shouldn't happen since
-		   we're waiting for TxOk, so return 1 and requeue this packet. */
-		restore_flags(flags);
+	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0)
+	{
+		/*
+		 * Gasp!  It hasn't.  But that shouldn't happen since
+		 * we're waiting for TxOk, so return 1 and requeue this packet.
+		 */
+		
+		spin_unlock_irq(&lp->lock);
+		if (net_debug) printk("cs89x0: Tx buffer not free!\n");
 		return 1;
 	}
 	/* Write the contents of the packet */
-        outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
-
-	restore_flags(flags);
+	outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+	spin_unlock_irq(&lp->lock);
 	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
-	netif_wake_queue(dev);
-	
+
+	/*
+	 * We DO NOT call netif_wake_queue() here.
+	 * We also DO NOT call netif_start_queue().
+	 *
+	 * Either of these would cause another bottom half run through
+	 * net_send_packet() before this packet has fully gone out.  That causes
+	 * us to hit the "Gasp!" above and the send is rescheduled.  it runs like
+	 * a dog.  We just return and wait for the Tx completion interrupt handler
+	 * to restart the netdevice layer
+	 */
+
 	return 0;
 }
 
@@ -771,7 +1204,7 @@
 	struct net_device *dev = dev_id;
 	struct net_local *lp;
 	int ioaddr, status;
-
+ 
 	ioaddr = dev->base_addr;
 	lp = (struct net_local *)dev->priv;
 
@@ -792,11 +1225,18 @@
 		case ISQ_TRANSMITTER_EVENT:
 			lp->stats.tx_packets++;
 			netif_wake_queue(dev);	/* Inform upper layers. */
-			if ((status & TX_OK) == 0) lp->stats.tx_errors++;
-			if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
-			if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
-			if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
-			if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+			if ((status & (	TX_OK |
+					TX_LOST_CRS |
+					TX_SQE_ERROR |
+					TX_LATE_COL |
+					TX_16_COL)) != TX_OK)
+			{
+				if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+				if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+				if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+				if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
+				if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+			}
 			break;
 		case ISQ_BUFFER_EVENT:
 			if (status & READY_FOR_TX) {
@@ -819,6 +1259,22 @@
 				   event of a tx underrun */
 				netif_wake_queue(dev);	/* Inform upper layers. */
                         }
+#if ALLOW_DMA
+			if (lp->use_dma && (status & RX_DMA)) {
+				int count = readreg(dev, PP_DmaFrameCnt);
+				while(count) {
+					if (net_debug > 5)
+						printk("%s: receiving %d DMA frames\n", dev->name, count);
+					if (net_debug > 2 && count >1)
+						printk("%s: receiving %d DMA frames\n", dev->name, count);
+					dma_rx(dev);
+					if (--count == 0)
+						count = readreg(dev, PP_DmaFrameCnt);
+					if (net_debug > 2 && count > 0)
+						printk("%s: continuing with %d DMA frames\n", dev->name, count);
+				}
+			}
+#endif
 			break;
 		case ISQ_RX_MISS_EVENT:
 			lp->stats.rx_missed_errors += (status >>6);
@@ -830,45 +1286,58 @@
 	}
 }
 
+static void
+count_rx_errors(int status, struct net_local *lp)
+{
+	lp->stats.rx_errors++;
+	if (status & RX_RUNT) lp->stats.rx_length_errors++;
+	if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
+	if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+		/* per str 172 */
+		lp->stats.rx_crc_errors++;
+	if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+	return;
+}
+
 /* We have a good packet(s), get it/them out of the buffers. */
 static void
 net_rx(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	int ioaddr = dev->base_addr;
 	struct sk_buff *skb;
 	int status, length;
 
+	int ioaddr = dev->base_addr;
 	status = inw(ioaddr + RX_FRAME_PORT);
 	length = inw(ioaddr + RX_FRAME_PORT);
+
 	if ((status & RX_OK) == 0) {
-		lp->stats.rx_errors++;
-		if (status & RX_RUNT) lp->stats.rx_length_errors++;
-		if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
-		if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
-			/* per str 172 */
-			lp->stats.rx_crc_errors++;
-		if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+		count_rx_errors(status, lp);
 		return;
 	}
 
 	/* Malloc up new buffer. */
 	skb = alloc_skb(length, GFP_ATOMIC);
 	if (skb == NULL) {
-		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+#if 0		/* Again, this seems a cruel thing to do */
+		printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+#endif
 		lp->stats.rx_dropped++;
 		return;
 	}
 	skb->len = length;
 	skb->dev = dev;
 
-        insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
+	insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
 	if (length & 1)
 		skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT);
 
-	if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
-                                 dev->name, length,
-                                 (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+	if (net_debug > 3)
+	{
+		printk(	"%s: received %d byte packet of type %x\n",
+			dev->name, length,
+			(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+	}
 
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
@@ -877,10 +1346,23 @@
 	return;
 }
 
+#if ALLOW_DMA
+static void release_dma_buff(struct net_local *lp)
+{
+	if (lp->dma_buff)
+	{
+		free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE);
+		lp->dma_buff = 0;
+	}
+}
+#endif
+
 /* The inverse routine to net_open(). */
 static int
 net_close(struct net_device *dev)
 {
+	struct net_local *lp = (struct net_local *)dev->priv;
+
 	netif_stop_queue(dev);
 	
 	writereg(dev, PP_RxCFG, 0);
@@ -890,11 +1372,16 @@
 
 	free_irq(dev->irq, dev);
 
-	/* Update the statistics here. */
+#if ALLOW_DMA
+	if (lp->use_dma && lp->dma) {
+		free_dma(dev->dma);
+		release_dma_buff(lp);
+	}
+#endif
 
+	/* Update the statistics here. */
         MOD_DEC_USE_COUNT;
 	return 0;
-
 }
 
 /* Get the current statistics.	This may be called with the card open or
@@ -903,12 +1390,13 @@
 net_get_stats(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
 
-	cli();
+	spin_lock_irqsave(&lp->lock, flags);
 	/* Update the statistics from the device registers. */
 	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
 	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
-	sti();
+	spin_unlock_irqrestore(&lp->lock, flags);
 
 	return &lp->stats;
 }
@@ -916,7 +1404,9 @@
 static void set_multicast_list(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
 
+	spin_lock_irqsave(&lp->lock, flags);
 	if(dev->flags&IFF_PROMISC)
 	{
 		lp->rx_mode = RX_ALL_ACCEPT;
@@ -935,18 +1425,23 @@
 	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
 	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
 	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+	spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 
 static int set_mac_address(struct net_device *dev, void *addr)
 {
 	int i;
+
 	if (netif_running(dev))
 		return -EBUSY;
-	printk("%s: Setting MAC address to ", dev->name);
-	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
-	printk(".\n");
+	if (net_debug)
+	{
+		printk("%s: Setting MAC address to ", dev->name);
+		for (i = 0; i < 6; i++)
+			printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+		printk(".\n");
+	}
 	/* set the Ethernet address */
 	for (i=0; i < ETH_ALEN/2; i++)
 		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
@@ -963,17 +1458,31 @@
         0, 0,
         0, 0, 0, NULL, NULL };
 
+/*
+ * Support the 'debug' module parm even if we're compiled for non-debug to 
+ * avoid breaking someone's startup scripts 
+ */
+
 static int io=0;
 static int irq=0;
 static int debug=0;
 static char media[8];
 static int duplex=-1;
 
+static int use_dma = 0;			/* These generate unused var warnings if ALLOW_DMA = 0 */
+static int dma=0;
+static int dmasize=16;			/* or 64 */
+
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(media, "s");
 MODULE_PARM(duplex, "i");
+MODULE_PARM(dma , "i");
+MODULE_PARM(dmasize , "i");
+MODULE_PARM(use_dma , "i");
+
+MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>");
 
 EXPORT_NO_SYMBOLS;
 
@@ -1008,15 +1517,34 @@
 {
 	struct net_local *lp;
 
+#if DEBUGGING
 	net_debug = debug;
+#endif
         dev_cs89x0.name = namespace;
 	dev_cs89x0.irq = irq;
 	dev_cs89x0.base_addr = io;
+
         dev_cs89x0.init = cs89x0_probe;
         dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if (dev_cs89x0.priv == 0)
+	{
+		printk(KERN_ERR "cs89x0.c: Out of memory.\n");
+		return -ENOMEM;
+	}
 	memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
 	lp = (struct net_local *)dev_cs89x0.priv;
 
+#if ALLOW_DMA
+	if (use_dma)
+	{
+		lp->use_dma = use_dma;
+		lp->dma = dma;
+		lp->dmasize = dmasize;
+	}
+#endif
+
+	spin_lock_init(&lp->lock);
+
         /* boy, they'd better get these right */
         if (!strcmp(media, "rj45"))
 		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
@@ -1031,12 +1559,20 @@
 		lp->auto_neg_cnf = AUTO_NEG_ENABLE;
 
         if (io == 0)  {
-                printk(KERN_NOTICE "cs89x0.c: Module autoprobing not allowed.\n");
-                printk(KERN_NOTICE "cs89x0.c: Append io=0xNNN\n");
+                printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n");
+                printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n");
                 return -EPERM;
         }
+
+#if ALLOW_DMA
+	if (use_dma && dmasize != 16 && dmasize != 64) {
+		printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize);
+		return -EPERM;
+	}
+#endif
+
         if (register_netdev(&dev_cs89x0) != 0) {
-                printk(KERN_WARNING "cs89x0.c: No card found at 0x%x\n", io);
+                printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);
                 return -ENXIO;
         }
 	return 0;
@@ -1045,13 +1581,7 @@
 void
 cleanup_module(void)
 {
-
-#endif
-#ifdef MODULE
-	outw(0, dev_cs89x0.base_addr + ADD_PORT);
-#endif
-#ifdef MODULE
-
+	outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT);
         if (dev_cs89x0.priv != NULL) {
                 /* Free up the private structure, or leak memory :-)  */
                 unregister_netdev(&dev_cs89x0);
diff -u --recursive --new-file v2.3.49/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h
--- v2.3.49/linux/drivers/net/cs89x0.h	Tue Feb  1 01:35:44 2000
+++ linux/drivers/net/cs89x0.h	Fri Mar  3 12:56:13 2000
@@ -217,6 +217,7 @@
 #define ENDEC_LOOPBACK 0x0200
 #define AUI_LOOPBACK 0x0400
 #define BACKOFF_OFF 0x0800
+#define FDX_8900 0x4000
 #define FAST_TEST 0x8000
 
 /* PP_RxEvent - Receive Event Bit definition - Read-only */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/ipddp.c linux/drivers/net/ipddp.c
--- v2.3.49/linux/drivers/net/ipddp.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/ipddp.c	Wed Dec 31 16:00:00 1969
@@ -1,358 +0,0 @@
-/*
- *	ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
- *		 Appletalk-IP to IP Decapsulation driver for Linux
- *
- *	Authors:
- *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *	- DDP-IP Decap by: Jay Schulist <jschlst@turbolinux.com>
- *
- *	Derived from:
- *	- Almost all code already existed in net/appletalk/ddp.c I just
- *	  moved/reorginized it into a driver file. Original IP-over-DDP code
- *	  was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *      - skeleton.c: A network driver outline for linux.
- *        Written 1993-94 by Donald Becker.
- *	- dummy.c: A dummy net driver. By Nick Holloway.
- *	- MacGate: A user space Daemon for Appletalk-IP Decap for
- *	  Linux by Jay Schulist <jschlst@turbolinux.com>
- *
- *      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.
- */
-
-static const char *version = 
-	"ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
-
-#include <linux/config.h>
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/atalk.h>
-#include <linux/ip.h>
-#include <net/route.h>
-#include <linux/inet.h>
-
-#include "ipddp.h"		/* Our stuff */
-
-static struct ipddp_route *ipddp_route_list = NULL;
-
-#ifdef CONFIG_IPDDP_ENCAP
-static int ipddp_mode = IPDDP_ENCAP;
-#else
-static int ipddp_mode = IPDDP_DECAP;
-#endif
-
-/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef IPDDP_DEBUG
-#define IPDDP_DEBUG 1
-#endif
-static unsigned int ipddp_debug = IPDDP_DEBUG;
-
-/* Index to functions, as function prototypes. */
-static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
-static int ipddp_create(struct ipddp_route *new_rt);
-static int ipddp_delete(struct ipddp_route *rt);
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
-static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-
-
-static int ipddp_open(struct net_device *dev)
-{
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
-
-        return 0;
-}
-
-static int ipddp_close(struct net_device *dev)
-{
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
-
-        return 0;
-}
-
-int ipddp_init(struct net_device *dev)
-{
-	static unsigned version_printed = 0;
-
-	if (ipddp_debug && version_printed++ == 0)
-                printk("%s", version);
-
-	/* Let the user now what mode we are in */
-	if(ipddp_mode == IPDDP_ENCAP)
-		printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
-			dev->name);
-	if(ipddp_mode == IPDDP_DECAP)
-		printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@turbolinux.com>\n", 
-			dev->name);
-
-	/* Fill in the device structure with ethernet-generic values. */
-        ether_setup(dev);
-
-	/* Initalize the device structure. */
-        dev->hard_start_xmit = ipddp_xmit;
-
-        dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
-        if(!dev->priv)
-                return -ENOMEM;
-        memset(dev->priv,0,sizeof(struct enet_statistics));
-
-	dev->open 	    = ipddp_open;
-        dev->stop 	    = ipddp_close;
-        dev->get_stats      = ipddp_get_stats;
-        dev->do_ioctl       = ipddp_ioctl;
-
-        dev->type = ARPHRD_IPDDP;       	/* IP over DDP tunnel */
-        dev->mtu = 585;
-        dev->flags |= IFF_NOARP;
-
-        /*
-         *      The worst case header we will need is currently a
-         *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
-         *      We send over SNAP so that takes another 8 bytes.
-         */
-        dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
-
-        return 0;
-}
-
-/*
- * Get the current statistics. This may be called with the card open or closed.
- */
-static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
-{
-        return (struct net_device_stats *)dev->priv;
-}
-
-/*
- * Transmit LLAP/ELAP frame using aarp_send_ddp.
- */
-static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
-        struct ddpehdr *ddp;
-        struct ipddp_route *rt;
-        struct at_addr *our_addr;
-
-	/*
-         * Find appropriate route to use, based only on IP number.
-         */
-        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
-        {
-                if(rt->ip == paddr)
-                        break;
-        }
-        if(rt == NULL)
-                return 0;
-
-        our_addr = atalk_find_dev_addr(rt->dev);
-
-	if(ipddp_mode == IPDDP_DECAP)
-		/* 
-		 * Pull off the excess room that should not be there.
-		 * This is due to a hard-header problem. This is the
-		 * quick fix for now though, till it breaks.
-		 */
-		skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
-
-	/* Create the Extended DDP header */
-	ddp = (struct ddpehdr *)skb->data;
-        ddp->deh_len = skb->len;
-        ddp->deh_hops = 1;
-        ddp->deh_pad = 0;
-        ddp->deh_sum = 0;
-
-	/*
-         * For Localtalk we need aarp_send_ddp to strip the
-         * long DDP header and place a shot DDP header on it.
-         */
-        if(rt->dev->type == ARPHRD_LOCALTLK)
-        {
-                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
-                ddp->deh_snet  = 0;
-        }
-        else
-        {
-                ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
-                ddp->deh_snet  = our_addr->s_net;
-        }
-        ddp->deh_dnode = rt->at.s_node;
-        ddp->deh_snode = our_addr->s_node;
-        ddp->deh_dport = 72;
-        ddp->deh_sport = 72;
-
-        *((__u8 *)(ddp+1)) = 22;        	/* ddp type = IP */
-        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));	/* fix up length field */
-
-        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
-
-	((struct net_device_stats *) dev->priv)->tx_packets++;
-        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
-
-        if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
-                dev_kfree_skb(skb);
-
-        return 0;
-}
-
-/*
- * Create a routing entry. We first verify that the
- * record does not already exist. If it does we return -EEXIST
- */
-static int ipddp_create(struct ipddp_route *new_rt)
-{
-        struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
-	struct ipddp_route *test;
-
-        if(rt == NULL)
-                return -ENOMEM;
-
-        rt->ip = new_rt->ip;
-        rt->at = new_rt->at;
-        rt->next = NULL;
-        rt->dev = atrtr_get_dev(&rt->at);
-        if(rt->dev == NULL)
-                return (-ENETUNREACH);
-
-	test = ipddp_find_route(rt);
-	if(test != NULL)
-		return (-EEXIST);
-	
-        rt->next = ipddp_route_list;
-        ipddp_route_list = rt;
-
-        return 0;
-}
-
-/*
- * Delete a route, we only delete a FULL match.
- * If route does not exist we return -ENOENT.
- */
-static int ipddp_delete(struct ipddp_route *rt)
-{
-        struct ipddp_route **r = &ipddp_route_list;
-        struct ipddp_route *tmp;
-
-        while((tmp = *r) != NULL)
-        {
-                if(tmp->ip == rt->ip
-                        && tmp->at.s_net == rt->at.s_net
-                        && tmp->at.s_node == rt->at.s_node)
-                {
-                        *r = tmp->next;
-                        kfree_s(tmp, sizeof(struct ipddp_route));
-                        return 0;
-                }
-                r = &tmp->next;
-        }
-
-        return (-ENOENT);
-}
-
-/*
- * Find a routing entry, we only return a FULL match
- */
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
-{
-        struct ipddp_route *f;
-
-        for(f = ipddp_route_list; f != NULL; f = f->next)
-        {
-                if(f->ip == rt->ip
-                        && f->at.s_net == rt->at.s_net
-                        && f->at.s_node == rt->at.s_node)
-                        return (f);
-        }
-
-        return (NULL);
-}
-
-static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-        struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
-
-        if(!capable(CAP_NET_ADMIN))
-                return -EPERM;
-
-        switch(cmd)
-        {
-		case SIOCADDIPDDPRT:
-                        return (ipddp_create(rt));
-
-                case SIOCFINDIPDDPRT:
-                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
-                                return -EFAULT;
-                        return 0;
-
-                case SIOCDELIPDDPRT:
-                        return (ipddp_delete(rt));
-
-                default:
-                        return -EINVAL;
-        }
-}
-
-#ifdef MODULE	/* Module specific functions for ipddp.c */
-
-static struct net_device dev_ipddp=
-{
-        "ipddp0\0   ",
-                0, 0, 0, 0,
-                0x0, 0,
-                0, 0, 0, NULL, ipddp_init
-};
-
-MODULE_PARM(ipddp_mode, "i");
-
-int init_module(void)
-{
-	int err;
-
-	err=dev_alloc_name(&dev_ipddp, "ipddp%d");
-        if(err < 0)
-                return err;
-
-	if(register_netdev(&dev_ipddp) != 0)
-                return -EIO;
-
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unregister_netdev(&dev_ipddp);
-        kfree(dev_ipddp.priv);
-	dev_ipddp.priv = NULL;
-}
-
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/ipddp.h linux/drivers/net/ipddp.h
--- v2.3.49/linux/drivers/net/ipddp.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/ipddp.h	Wed Dec 31 16:00:00 1969
@@ -1,27 +0,0 @@
-/*
- *	ipddp.h: Header for IP-over-DDP driver for Linux.
- */
-
-#ifndef __LINUX_IPDDP_H
-#define __LINUX_IPDDP_H
-
-#ifdef __KERNEL__
-
-#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
-#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
-#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
-
-struct ipddp_route
-{
-        struct net_device *dev;             /* Carrier device */
-        __u32 ip;                       /* IP address */
-        struct at_addr at;              /* Gateway appletalk address */
-        int flags;
-        struct ipddp_route *next;
-};
-
-#define IPDDP_ENCAP	1
-#define IPDDP_DECAP	2
-
-#endif	/* __KERNEL__ */
-#endif	/* __LINUX_IPDDP_H */
diff -u --recursive --new-file v2.3.49/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
--- v2.3.49/linux/drivers/net/ltpc.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/net/ltpc.c	Wed Dec 31 16:00:00 1969
@@ -1,1364 +0,0 @@
-/***    ltpc.c -- a driver for the LocalTalk PC card.
- *
- *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *
- *      This software may be used and distributed according to the terms
- *      of the GNU General Public License, incorporated herein by reference.
- *
- *      This is ALPHA code at best.  It may not work for you.  It may
- *      damage your equipment.  It may damage your relations with other
- *      users of your network.  Use it at your own risk!
- *
- *      Based in part on:
- *      skeleton.c      by Donald Becker
- *      dummy.c         by Nick Holloway and Alan Cox
- *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
- *      the netatalk source code (UMICH)
- *      lots of work on the card...
- *
- *      I do not have access to the (proprietary) SDK that goes with the card.
- *      If you do, I don't want to know about it, and you can probably write
- *      a better driver yourself anyway.  This does mean that the pieces that
- *      talk to the card are guesswork on my part, so use at your own risk!
- *
- *      This is my first try at writing Linux networking code, and is also
- *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
- *      welcome suggestions)
- *
- *      This is a loadable kernel module which seems to work at my site
- *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
- *      the kernel support from 1.3.3b2 including patches routing.patch
- *      and ddp.disappears.from.chooser.  In order to run it, you will need
- *      to patch ddp.c and aarp.c in the kernel, but only a little...
- *
- *      I'm fairly confident that while this is arguably badly written, the
- *      problems that people experience will be "higher level", that is, with
- *      complications in the netatalk code.  The driver itself doesn't do
- *      anything terribly complicated -- it pretends to be an ether device
- *      as far as netatalk is concerned, strips the DDP data out of the ether
- *      frame and builds a LLAP packet to send out the card.  In the other
- *      direction, it receives LLAP frames from the card and builds a fake
- *      ether packet that it then tosses up to the networking code.  You can
- *      argue (correctly) that this is an ugly way to do things, but it
- *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
- *
- *      The card will do a lot more than is used here -- I *think* it has the
- *      layers up through ATP.  Even if you knew how that part works (which I
- *      don't) it would be a big job to carve up the kernel ddp code to insert
- *      things at a higher level, and probably a bad idea...
- *
- *      There are a number of other cards that do LocalTalk on the PC.  If
- *      nobody finds any insurmountable (at the netatalk level) problems
- *      here, this driver should encourage people to put some work into the
- *      other cards (some of which I gather are still commercially available)
- *      and also to put hooks for LocalTalk into the official ddp code.
- *
- *      I welcome comments and suggestions.  This is my first try at Linux
- *      networking stuff, and there are probably lots of things that I did
- *      suboptimally.  
- *
- ***/
-
-/***
- *
- * $Log: ltpc.c,v $
- * Revision 1.8  1997/01/28 05:44:54  bradford
- * Clean up for non-module a little.
- * Hacked about a bit to clean things up - Alan Cox 
- * Probably broken it from the origina 1.8
- *
-
- * 1998/11/09: David Huggins-Daines <dhd@debian.org>
- * Cleaned up the initialization code to use the standard autoirq methods,
-   and to probe for things in the standard order of i/o, irq, dma.  This
-   removes the "reset the reset" hack, because I couldn't figure out an
-   easy way to get the card to trigger an interrupt after it.
- * Added support for passing configuration parameters on the kernel command
-   line and through insmod
- * Changed the device name from "ltalk0" to "lt0", both to conform with the
-   other localtalk driver, and to clear up the inconsistency between the
-   module and the non-module versions of the driver :-)
- * Added a bunch of comments (I was going to make some enums for the state
-   codes and the register offsets, but I'm still not sure exactly what their
-   semantics are)
- * Don't poll anymore in interrupt-driven mode
- * It seems to work as a module now (as of 2.1.127), but I don't think
-   I'm responsible for that...
-
- *
- * Revision 1.7  1996/12/12 03:42:33  bradford
- * DMA alloc cribbed from 3c505.c.
- *
- * Revision 1.6  1996/12/12 03:18:58  bradford
- * Added virt_to_bus; works in 2.1.13.
- *
- * Revision 1.5  1996/12/12 03:13:22  root
- * xmitQel initialization -- think through better though.
- *
- * Revision 1.4  1996/06/18 14:55:55  root
- * Change names to ltpc. Tabs. Took a shot at dma alloc,
- * although more needs to be done eventually.
- *
- * Revision 1.3  1996/05/22 14:59:39  root
- * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
- *
- * Revision 1.2  1996/05/22 14:58:24  root
- * Change tabs mostly.
- *
- * Revision 1.1  1996/04/23 04:45:09  root
- * Initial revision
- *
- * Revision 0.16  1996/03/05 15:59:56  root
- * Change ARPHRD_LOCALTLK definition to the "real" one.
- *
- * Revision 0.15  1996/03/05 06:28:30  root
- * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
- * it's getting closer.
- *
- * Revision 0.14  1996/02/25 17:38:32  root
- * More cleanups.  Removed query to card on get_stats.
- *
- * Revision 0.13  1996/02/21  16:27:40  root
- * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
- * Clean up receive code a little.
- *
- * Revision 0.12  1996/02/19  16:34:53  root
- * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
- * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
- * including packet printing, 4 for lower level (card i/o) stuff.
- *
- * Revision 0.11  1996/02/12  15:53:38  root
- * Added router sends (requires new aarp.c patch)
- *
- * Revision 0.10  1996/02/11  00:19:35  root
- * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
- *
- * Revision 0.9  1996/02/10  23:59:35  root
- * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
- * has a *different* definition of struct sockaddr_at than the Linux kernel
- * does.  This is an "insidious and invidious" bug...
- * (Actually the preceding comment is false -- it's the atalk.h in the
- * ancient atalk-0.06 that's the problem)
- *
- * Revision 0.8  1996/02/10 19:09:00  root
- * Merge 1.3 changes.  Tested OK under 1.3.60.
- *
- * Revision 0.7  1996/02/10 17:56:56  root
- * Added debug=1 parameter on insmod for debugging prints.  Tried
- * to fix timer unload on rmmod, but I don't think that's the problem.
- *
- * Revision 0.6  1995/12/31  19:01:09  root
- * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
- * Clean up initial probing -- sometimes the card wakes up latched in reset.
- *
- * Revision 0.5  1995/12/22  06:03:44  root
- * Added comments in front and cleaned up a bit.
- * This version sent out to people.
- *
- * Revision 0.4  1995/12/18  03:46:44  root
- * Return shortDDP to longDDP fake to 0/0.  Added command structs.
- *
- ***/
-
-/* ltpc jumpers are:
-*
-*	Interrupts -- set at most one.  If none are set, the driver uses
-*	polled mode.  Because the card was developed in the XT era, the
-*	original documentation refers to IRQ2.  Since you'll be running
-*	this on an AT (or later) class machine, that really means IRQ9.
-*
-*	SW1	IRQ 4
-*	SW2	IRQ 3
-*	SW3	IRQ 9 (2 in original card documentation only applies to XT)
-*
-*
-*	DMA -- choose DMA 1 or 3, and set both corresponding switches.
-*
-*	SW4	DMA 3
-*	SW5	DMA 1
-*	SW6	DMA 3
-*	SW7	DMA 1
-*
-*
-*	I/O address -- choose one.  
-*
-*	SW8	220 / 240
-*/
-
-/*	To have some stuff logged, do 
-*	insmod ltpc.o debug=1
-*
-*	For a whole bunch of stuff, use higher numbers.
-*
-*	The default is 0, i.e. no messages except for the probe results.
-*/
-
-/* insmod-tweakable variables */
-static int debug=0;
-#define DEBUG_VERBOSE 1
-#define DEBUG_UPPER 2
-#define DEBUG_LOWER 4
-
-static int io=0;
-static int irq=0;
-static int dma=0;
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <linux/if_arp.h>
-#include <linux/if_ltalk.h>
-
-#include <linux/delay.h>
-#include <linux/timer.h>
-
-#include <linux/atalk.h>
-
-/* our stuff */
-#include "ltpc.h"
-
-/* function prototypes */
-static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
-	void *dbuf, int dbuflen);
-static int sendup_buffer (struct net_device *dev);
-
-/* Dma Memory related stuff, cribbed directly from 3c505.c */
-
-static unsigned long dma_mem_alloc(int size)
-{
-        int order = get_order(size);
-
-        return __get_dma_pages(GFP_KERNEL, order);
-}
-
-/* DMA data buffer, DMA command buffer */
-static unsigned char *ltdmabuf;
-static unsigned char *ltdmacbuf;
-
-/* private struct, holds our appletalk address */
-
-struct ltpc_private
-{
-	struct net_device_stats stats;
-	struct at_addr my_addr;
-};
-
-/* transmit queue element struct */
-
-struct xmitQel {
-	struct xmitQel *next;
-	/* command buffer */
-	unsigned char *cbuf;
-	short cbuflen;
-	/* data buffer */
-	unsigned char *dbuf;
-	short dbuflen;
-	unsigned char QWrite;	/* read or write data */
-	unsigned char mailbox;
-};
-
-/* the transmit queue itself */
-
-static struct xmitQel *xmQhd=NULL,*xmQtl=NULL;
-
-static void enQ(struct xmitQel *qel)
-{
-	unsigned long flags;
-	qel->next = NULL;
-	save_flags(flags);
-	cli();
-	if (xmQtl) {
-		xmQtl->next = qel;
-	} else {
-		xmQhd = qel;
-	}
-	xmQtl = qel;
-	restore_flags(flags);
-
-	if (debug&DEBUG_LOWER)
-		printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
-}
-
-static struct xmitQel *deQ(void)
-{
-	unsigned long flags;
-	int i;
-	struct xmitQel *qel=NULL;
-	save_flags(flags);
-	cli();
-	if (xmQhd) {
-		qel = xmQhd;
-		xmQhd = qel->next;
-		if(!xmQhd) xmQtl = NULL;
-	}
-	restore_flags(flags);
-
-	if ((debug&DEBUG_LOWER) && qel) {
-		int n;
-		printk("ltpc: dequeued command ");
-		n = qel->cbuflen;
-		if (n>100) n=100;
-		for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
-		printk("\n");
-	}
-
-	return qel;
-}
-
-/* and... the queue elements we'll be using */
-static struct xmitQel qels[16];
-
-/* and their corresponding mailboxes */
-static unsigned char mailbox[16];
-static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-static int wait_timeout(struct net_device *dev, int c)
-{
-	/* returns true if it stayed c */
-	/* this uses base+6, but it's ok */
-	int i;
-	int timeout;
-
-	/* twenty second or so total */
-
-	for(i=0;i<20000;i++) {
-		if ( c != inb_p(dev->base_addr+6) ) return 0;
-		for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
-	}
-	return 1; /* timed out */
-}
-
-/* get the first free mailbox */
-
-static int getmbox(void)
-{
-	unsigned long flags;
-	int i;
-
-	save_flags(flags);
-	cli();
-	for(i=1;i<16;i++) if(!mboxinuse[i]) {
-		mboxinuse[i]=1;
-		restore_flags(flags);
-		return i;
-	}
-	restore_flags(flags);
-	return 0;
-}
-
-/* read a command from the card */
-static void handlefc(struct net_device *dev)
-{
-	/* called *only* from idle, non-reentrant */
-	int dma = dev->dma;
-	int base = dev->base_addr;
-	unsigned long flags;
-
-
-	flags=claim_dma_lock();
-	disable_dma(dma);
-	clear_dma_ff(dma);
-	set_dma_mode(dma,DMA_MODE_READ);
-	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
-	set_dma_count(dma,50);
-	enable_dma(dma);
-	release_dma_lock(flags);
-
-	inb_p(base+3);
-	inb_p(base+2);
-
-	if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
-}
-
-/* read data from the card */
-static void handlefd(struct net_device *dev)
-{
-	int dma = dev->dma;
-	int base = dev->base_addr;
-	unsigned long flags;
-
-	flags=claim_dma_lock();
-	disable_dma(dma);
-	clear_dma_ff(dma);
-	set_dma_mode(dma,DMA_MODE_READ);
-	set_dma_addr(dma,virt_to_bus(ltdmabuf));
-	set_dma_count(dma,800);
-	enable_dma(dma);
-	release_dma_lock(flags);
-
-	inb_p(base+3);
-	inb_p(base+2);
-
-	if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
-	sendup_buffer(dev);
-} 
-
-static void handlewrite(struct net_device *dev)
-{
-	/* called *only* from idle, non-reentrant */
-	/* on entry, 0xfb and ltdmabuf holds data */
-	int dma = dev->dma;
-	int base = dev->base_addr;
-	unsigned long flags;
-	
-	flags=claim_dma_lock();
-	disable_dma(dma);
-	clear_dma_ff(dma);
-	set_dma_mode(dma,DMA_MODE_WRITE);
-	set_dma_addr(dma,virt_to_bus(ltdmabuf));
-	set_dma_count(dma,800);
-	enable_dma(dma);
-	release_dma_lock(flags);
-	
-	inb_p(base+3);
-	inb_p(base+2);
-
-	if ( wait_timeout(dev,0xfb) ) {
-		flags=claim_dma_lock();
-		printk("timed out in handlewrite, dma res %d\n",
-			get_dma_residue(dev->dma) );
-		release_dma_lock(flags);
-	}
-}
-
-static void handleread(struct net_device *dev)
-{
-	/* on entry, 0xfb */
-	/* on exit, ltdmabuf holds data */
-	int dma = dev->dma;
-	int base = dev->base_addr;
-	unsigned long flags;
-
-	
-	flags=claim_dma_lock();
-	disable_dma(dma);
-	clear_dma_ff(dma);
-	set_dma_mode(dma,DMA_MODE_READ);
-	set_dma_addr(dma,virt_to_bus(ltdmabuf));
-	set_dma_count(dma,800);
-	enable_dma(dma);
-	release_dma_lock(flags);
-
-	inb_p(base+3);
-	inb_p(base+2);
-	if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
-}
-
-static void handlecommand(struct net_device *dev)
-{
-	/* on entry, 0xfa and ltdmacbuf holds command */
-	int dma = dev->dma;
-	int base = dev->base_addr;
-	unsigned long flags;
-
-	flags=claim_dma_lock();
-	disable_dma(dma);
-	clear_dma_ff(dma);
-	set_dma_mode(dma,DMA_MODE_WRITE);
-	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
-	set_dma_count(dma,50);
-	enable_dma(dma);
-	release_dma_lock(flags);
-	inb_p(base+3);
-	inb_p(base+2);
-	if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
-} 
-
-/* ready made command for getting the result from the card */
-static unsigned char rescbuf[2] = {LT_GETRESULT,0};
-static unsigned char resdbuf[2];
-
-static int QInIdle=0;
-
-/* idle expects to be called with the IRQ line high -- either because of
- * an interrupt, or because the line is tri-stated
- */
-
-static void idle(struct net_device *dev)
-{
-	unsigned long flags;
-	int state;
-	/* FIXME This is initialized to shut the warning up, but I need to
-	 * think this through again.
-	 */
-	struct xmitQel *q=0;
-	int oops;
-	int i;
-	int base = dev->base_addr;
-
-	save_flags(flags);
-	cli();
-	if(QInIdle) {
-		restore_flags(flags);
-		return;
-	}
-	QInIdle = 1;
-
-
-	restore_flags(flags);
-
-	/* this tri-states the IRQ line */
-	(void) inb_p(base+6);
-
-	oops = 100;
-
-loop:
-	if (0>oops--) { 
-		printk("idle: looped too many times\n");
-		goto done;
-	}
-
-	state = inb_p(base+6);
-	if (state != inb_p(base+6)) goto loop;
-
-	switch(state) {
-		case 0xfc:
-			/* incoming command */
-			if (debug&DEBUG_LOWER) printk("idle: fc\n");
-			handlefc(dev); 
-			break;
-		case 0xfd:
-			/* incoming data */
-			if(debug&DEBUG_LOWER) printk("idle: fd\n");
-			handlefd(dev); 
-			break;
-		case 0xf9:
-			/* result ready */
-			if (debug&DEBUG_LOWER) printk("idle: f9\n");
-			if(!mboxinuse[0]) {
-				mboxinuse[0] = 1;
-				qels[0].cbuf = rescbuf;
-				qels[0].cbuflen = 2;
-				qels[0].dbuf = resdbuf;
-				qels[0].dbuflen = 2;
-				qels[0].QWrite = 0;
-				qels[0].mailbox = 0;
-				enQ(&qels[0]);
-			}
-			inb_p(dev->base_addr+1);
-			inb_p(dev->base_addr+0);
-			if( wait_timeout(dev,0xf9) )
-				printk("timed out idle f9\n");
-			break;
-		case 0xf8:
-			/* ?? */
-			if (xmQhd) {
-				inb_p(dev->base_addr+1);
-				inb_p(dev->base_addr+0);
-				if(wait_timeout(dev,0xf8) )
-					printk("timed out idle f8\n");
-			} else {
-				goto done;
-			}
-			break;
-		case 0xfa:
-			/* waiting for command */
-			if(debug&DEBUG_LOWER) printk("idle: fa\n");
-			if (xmQhd) {
-				q=deQ();
-				memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
-				ltdmacbuf[1] = q->mailbox;
-				if (debug>1) { 
-					int n;
-					printk("ltpc: sent command     ");
-					n = q->cbuflen;
-					if (n>100) n=100;
-					for(i=0;i<n;i++)
-						printk("%02x ",ltdmacbuf[i]);
-					printk("\n");
-				}
-				handlecommand(dev);
-					if(0xfa==inb_p(base+6)) {
-						/* we timed out, so return */
-						goto done;
-					} 
-			} else {
-				/* we don't seem to have a command */
-				if (!mboxinuse[0]) {
-					mboxinuse[0] = 1;
-					qels[0].cbuf = rescbuf;
-					qels[0].cbuflen = 2;
-					qels[0].dbuf = resdbuf;
-					qels[0].dbuflen = 2;
-					qels[0].QWrite = 0;
-					qels[0].mailbox = 0;
-					enQ(&qels[0]);
-				} else {
-					printk("trouble: response command already queued\n");
-					goto done;
-				}
-			} 
-			break;
-		case 0Xfb:
-			/* data transfer ready */
-			if(debug&DEBUG_LOWER) printk("idle: fb\n");
-			if(q->QWrite) {
-				memcpy(ltdmabuf,q->dbuf,q->dbuflen);
-				handlewrite(dev);
-			} else {
-				handleread(dev);
-				/* non-zero mailbox numbers are for
-				   commmands, 0 is for GETRESULT
-				   requests */
-				if(q->mailbox) {
-					memcpy(q->dbuf,ltdmabuf,q->dbuflen);
-				} else { 
-					/* this was a result */
-					mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
-					mboxinuse[0]=0;
-				}
-			}
-			break;
-	}
-	goto loop;
-
-done:
-	QInIdle=0;
-
-	/* now set the interrupts back as appropriate */
-	/* the first read takes it out of tri-state (but still high) */
-	/* the second resets it */
-	/* note that after this point, any read of base+6 will
-	   trigger an interrupt */
-
-	if (dev->irq) {
-		inb_p(base+7);
-		inb_p(base+7);
-	}
-	return;
-}
-
-
-static int do_write(struct net_device *dev, void *cbuf, int cbuflen,
-	void *dbuf, int dbuflen)
-{
-
-	int i = getmbox();
-	int ret;
-
-	if(i) {
-		qels[i].cbuf = (unsigned char *) cbuf;
-		qels[i].cbuflen = cbuflen;
-		qels[i].dbuf = (unsigned char *) dbuf;
-		qels[i].dbuflen = dbuflen;
-		qels[i].QWrite = 1;
-		qels[i].mailbox = i;  /* this should be initted rather */
-		enQ(&qels[i]);
-		idle(dev);
-		ret = mailbox[i];
-		mboxinuse[i]=0;
-		return ret;
-	}
-	printk("ltpc: could not allocate mbox\n");
-	return -1;
-}
-
-static int do_read(struct net_device *dev, void *cbuf, int cbuflen,
-	void *dbuf, int dbuflen)
-{
-
-	int i = getmbox();
-	int ret;
-
-	if(i) {
-		qels[i].cbuf = (unsigned char *) cbuf;
-		qels[i].cbuflen = cbuflen;
-		qels[i].dbuf = (unsigned char *) dbuf;
-		qels[i].dbuflen = dbuflen;
-		qels[i].QWrite = 0;
-		qels[i].mailbox = i;  /* this should be initted rather */
-		enQ(&qels[i]);
-		idle(dev);
-		ret = mailbox[i];
-		mboxinuse[i]=0;
-		return ret;
-	}
-	printk("ltpc: could not allocate mbox\n");
-	return -1;
-}
-
-/* end of idle handlers -- what should be seen is do_read, do_write */
-
-static struct timer_list ltpc_timer;
-
-static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ltpc_get_stats(struct net_device *dev);
-
-static int ltpc_open(struct net_device *dev)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-	return 0;
-}
-
-static int ltpc_close(struct net_device *dev)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-	return 0;
-}
-
-static int read_30 ( struct net_device *dev)
-{
-	lt_command c;
-	c.getflags.command = LT_GETFLAGS;
-	return do_read(dev, &c, sizeof(c.getflags),&c,0);
-}
-
-static int set_30 (struct net_device *dev,int x)
-{
-	lt_command c;
-	c.setflags.command = LT_SETFLAGS;
-	c.setflags.flags = x;
-	return do_write(dev, &c, sizeof(c.setflags),&c,0);
-}
-
-/* LLAP to DDP translation */
-
-static int sendup_buffer (struct net_device *dev)
-{
-	/* on entry, command is in ltdmacbuf, data in ltdmabuf */
-	/* called from idle, non-reentrant */
-
-	int dnode, snode, llaptype, len; 
-	int sklen;
-	struct sk_buff *skb;
-	struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
-	struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
-
-	if (ltc->command != LT_RCVLAP) {
-		printk("unknown command 0x%02x from ltpc card\n",ltc->command);
-		return(-1);
-	}
-	dnode = ltc->dnode;
-	snode = ltc->snode;
-	llaptype = ltc->laptype;
-	len = ltc->length; 
-
-	sklen = len;
-	if (llaptype == 1) 
-		sklen += 8;  /* correct for short ddp */
-	if(sklen > 800) {
-		printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
-			dev->name,sklen);
-		return -1;
-	}
-
-	if ( (llaptype==0) || (llaptype>2) ) {
-		printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
-		return -1;
-	}
-
-
-	skb = dev_alloc_skb(3+sklen);
-	if (skb == NULL) 
-	{
-		printk("%s: dropping packet due to memory squeeze.\n",
-			dev->name);
-		return -1;
-	}
-	skb->dev = dev;
-
-	if (sklen > len)
-		skb_reserve(skb,8);
-	skb_put(skb,len+3);
-	skb->protocol = htons(ETH_P_LOCALTALK);
-	/* add LLAP header */
-	skb->data[0] = dnode;
-	skb->data[1] = snode;
-	skb->data[2] = llaptype;
-	skb->mac.raw = skb->data;	/* save pointer to llap header */
-	skb_pull(skb,3);
-
-	/* copy ddp(s,e)hdr + contents */
-	memcpy(skb->data,(void*)ltdmabuf,len);
-
-	skb->h.raw = skb->data;
-
-	stats->rx_packets++;
-	stats->rx_bytes+=skb->len;
-
-	/* toss it onwards */
-	netif_rx(skb);
-	return 0;
-}
-
-/* the handler for the board interrupt */
- 
-static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
-{
-	struct net_device *dev = dev_id;
-
-	if (dev==NULL) {
-		printk("ltpc_interrupt: unknown device.\n");
-		return;
-	}
-
-	inb_p(dev->base_addr+6);  /* disable further interrupts from board */
-
-	idle(dev); /* handle whatever is coming in */
- 
-	/* idle re-enables interrupts from board */ 
-
-	return;
-}
-
-/***
- *
- *    The ioctls that the driver responds to are:
- *
- *    SIOCSIFADDR -- do probe using the passed node hint.
- *    SIOCGIFADDR -- return net, node.
- *
- *    some of this stuff should be done elsewhere.
- *
- ***/
-
-static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
-	/* we'll keep the localtalk node address in dev->pa_addr */
-	struct at_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr;
-	struct lt_init c;
-	int ltflags;
-
-	if(debug&DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
-
-	switch(cmd) {
-		case SIOCSIFADDR:
-
-			aa->s_net  = sa->sat_addr.s_net;
-      
-			/* this does the probe and returns the node addr */
-			c.command = LT_INIT;
-			c.hint = sa->sat_addr.s_node;
-
-			aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
-
-			/* get all llap frames raw */
-			ltflags = read_30(dev);
-			ltflags |= LT_FLAG_ALLLAP;
-			set_30 (dev,ltflags);  
-
-			dev->broadcast[0] = 0xFF;
-			dev->dev_addr[0] = aa->s_node;
-
-			dev->addr_len=1;
-   
-			return 0;
-
-		case SIOCGIFADDR:
-
-			sa->sat_addr.s_net = aa->s_net;
-			sa->sat_addr.s_node = aa->s_node;
-
-			return 0;
-
-		default: 
-			return -EINVAL;
-	}
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	/* This needs to be present to keep netatalk happy. */
-	/* Actually netatalk needs fixing! */
-}
-
-static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, 
-	unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-	if(debug&DEBUG_VERBOSE)
-		printk("ltpc_hard_header called for device %s\n",
-			dev->name);
-	return 0;
-}
-
-static int ltpc_init(struct net_device *dev)
-{
-	/* Initialize the device structure. */
-  
-	/* Fill in the fields of the device structure with ethernet-generic values. */
-	ltalk_setup(dev);
-	dev->hard_start_xmit = ltpc_xmit;
-	dev->hard_header = ltpc_hard_header;
-
-	dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL);
-	if(!dev->priv)
-	{
-		printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name);
-		return -ENOMEM;
-	}
-
-	memset(dev->priv, 0, sizeof(struct ltpc_private));
-	dev->get_stats = ltpc_get_stats;
-
-	dev->open = ltpc_open;
-	dev->stop = ltpc_close;
-
-	/* add the ltpc-specific things */
-	dev->do_ioctl = &ltpc_ioctl;
-
-	dev->set_multicast_list = &set_multicast_list;
-	dev->mc_list = NULL;
-
-	return 0;
-}
-
-static int ltpc_poll_counter = 0;
-
-static void ltpc_poll(unsigned long l)
-{
-	struct net_device *dev = (struct net_device *) l;
-
-	del_timer(&ltpc_timer);
-
-	if(debug&DEBUG_VERBOSE) {
-		if (!ltpc_poll_counter) {
-			ltpc_poll_counter = 50;
-			printk("ltpc poll is alive\n");
-		}
-		ltpc_poll_counter--;
-	}
-  
-	if (!dev)
-		return;  /* we've been downed */
-
-	idle(dev);
-	ltpc_timer.expires = jiffies+5;
-	
-	add_timer(&ltpc_timer);
-}
-
-/* DDP to LLAP translation */
-
-static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	/* in kernel 1.3.xx, on entry skb->data points to ddp header,
-	 * and skb->len is the length of the ddp data + ddp header
-	 */
-
-	struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
-
-	int i;
-	struct lt_sendlap cbuf;
-
-	cbuf.command = LT_SENDLAP;
-	cbuf.dnode = skb->data[0];
-	cbuf.laptype = skb->data[2];
-	skb_pull(skb,3);	/* skip past LLAP header */
-	cbuf.length = skb->len;	/* this is host order */
-	skb->h.raw=skb->data;
-
-	if(debug&DEBUG_UPPER) {
-		printk("command ");
-		for(i=0;i<6;i++)
-			printk("%02x ",((unsigned char *)&cbuf)[i]);
-		printk("\n");
-	}
-
-	do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
-
-	if(debug&DEBUG_UPPER) {
-		printk("sent %d ddp bytes\n",skb->len);
-		for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
-		printk("\n");
-	}
-
-	stats->tx_packets++;
-	stats->tx_bytes+=skb->len;
-
-	dev_kfree_skb(skb);
-	return 0;
-}
-
-static struct net_device_stats *ltpc_get_stats(struct net_device *dev)
-{
-	struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats;
-	return stats;
-}
-
-/* initialization stuff */
-  
-int __init ltpc_probe_dma(int base)
-{
-	int dma = 0;
-  	int timeout;
-  	unsigned long f;
-  
-  	if (!request_dma(1,"ltpc")) {
-  		f=claim_dma_lock();
-  		disable_dma(1);
-  		clear_dma_ff(1);
-		set_dma_mode(1,DMA_MODE_WRITE);
-		set_dma_addr(1,virt_to_bus(ltdmabuf));
-		set_dma_count(1,sizeof(struct lt_mem));
-		enable_dma(1);
-		release_dma_lock(f);
-		dma|=1;
-	}
-	if (!request_dma(3,"ltpc")) {
-		f=claim_dma_lock();
-		disable_dma(3);
-		clear_dma_ff(3);
-		set_dma_mode(3,DMA_MODE_WRITE);
-		set_dma_addr(3,virt_to_bus(ltdmabuf));
-		set_dma_count(3,sizeof(struct lt_mem));
-		enable_dma(3);
-		release_dma_lock(f);
-		dma|=2;
-	}
-
-	/* set up request */
-
-	/* FIXME -- do timings better! */
-
-	ltdmabuf[0] = LT_READMEM;
-	ltdmabuf[1] = 1;  /* mailbox */
-	ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
-	ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
-	ltdmabuf[6] = 0; /* dunno if this is necessary */
-
-	inb_p(io+1);
-	inb_p(io+0);
-	timeout = jiffies+100*HZ/100;
-	while(time_before(jiffies, timeout)) {
-		if ( 0xfa == inb_p(io+6) ) break;
-	}
-
-	inb_p(io+3);
-	inb_p(io+2);
-	while(time_before(jiffies, timeout)) {
-		if ( 0xfb == inb_p(io+6) ) break;
-	}
-
-	/* release the other dma channel (if we opened both of them) */
-
-	if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){
-		dma&=1;
-		free_dma(3);
-	}
-  
-	if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){
-		dma&=0x2;
-		free_dma(1);
-	}
-
-	/* fix up dma number */
-	dma|=1;
-
-	return dma;
-}
-
-int __init ltpc_probe(struct net_device *dev)
-{
-	int err;
-	int x=0,y=0;
-	int timeout;
-	int autoirq;
-	unsigned long flags;
-	unsigned long f;
-
-	save_flags(flags);
-
-	/* probe for the I/O port address */
-	if (io != 0x240 && !check_region(0x220,8)) {
-		x = inb_p(0x220+6);
-		if ( (x!=0xff) && (x>=0xf0) ) io = 0x220;
-	}
-	
-	if (io != 0x220 && !check_region(0x240,8)) {
-		y = inb_p(0x240+6);
-		if ( (y!=0xff) && (y>=0xf0) ) io = 0x240;
-	} 
-
-	if(io) {
-		/* found it, now grab it */
-		request_region(io,8,"ltpc");
-	} else {
-		/* give up in despair */
-		printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n",
-			x,y);
-		restore_flags(flags);
-		return -1;
-	}
-
-	/* probe for the IRQ line */
-	if (irq < 2) {
-		autoirq_setup(2);
-
-		/* reset the interrupt line */
-		inb_p(io+7);
-		inb_p(io+7);
-		/* trigger an interrupt (I hope) */
-		inb_p(io+6);
-
-		autoirq = autoirq_report(1);
-
-		if (autoirq == 0) {
-			printk("ltpc: probe at %#x failed to detect IRQ line.\n",
-				io);
-		}
-		else {
-			irq = autoirq;
-		}
-	}
-
-	/* allocate a DMA buffer */
-	ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
-
-	if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
-
-	if (!ltdmabuf) {
-		printk("ltpc: mem alloc failed\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	if(debug&DEBUG_VERBOSE) {
-		printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
-	}
-
-	/* reset the card */
-
-	inb_p(io+1);
-	inb_p(io+3);
-	timeout = jiffies+2*HZ/100;
-	while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */
-	inb_p(io+0);
-	inb_p(io+2);
-	inb_p(io+7); /* clear reset */
-	inb_p(io+4); 
-	inb_p(io+5);
-	inb_p(io+5); /* enable dma */
-	inb_p(io+6); /* tri-state interrupt line */
-
-	timeout = jiffies+100*HZ/100;
-	
-	while(time_before(jiffies, timeout)) {
-		/* wait for the card to complete initialization */
-	}
- 
-	/* now, figure out which dma channel we're using, unless it's
-	   already been specified */
-	/* well, 0 is a legal DMA channel, but the LTPC card doesn't
-	   use it... */
-	if (dma == 0) {
-		dma = ltpc_probe_dma(io);
-		if (!dma) {  /* no dma channel */
-			printk("No DMA channel found on ltpc card.\n");
-			restore_flags(flags);
-			return -1;
-		}
-	}
-
-	/* print out friendly message */
-
-	if(irq)
-		printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
-	else
-		printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
-
-	/* seems more logical to do this *after* probing the card... */
-	err = ltpc_init(dev);
-	if (err) return err;
-
-	dev->base_addr = io;
-	dev->irq = irq;
-	dev->dma = dma;
-
-	/* the card will want to send a result at this point */
-	/* (I think... leaving out this part makes the kernel crash,
-           so I put it back in...) */
-
-	f=claim_dma_lock();
-	disable_dma(dma);
-	clear_dma_ff(dma);
-	set_dma_mode(dma,DMA_MODE_READ);
-	set_dma_addr(dma,virt_to_bus(ltdmabuf));
-	set_dma_count(dma,0x100);
-	enable_dma(dma);
-	release_dma_lock(f);
-
-	(void) inb_p(io+3);
-	(void) inb_p(io+2);
-	timeout = jiffies+100*HZ/100;
-	while(time_before(jiffies, timeout)) {
-		if( 0xf9 == inb_p(io+6)) break;
-	}
-
-	if(debug&DEBUG_VERBOSE) {
-		printk("setting up timer and irq\n");
-	}
-
-	if (irq) {
-		/* grab it and don't let go :-) */
-		(void) request_irq( irq, &ltpc_interrupt, 0, "ltpc", dev);
-		(void) inb_p(io+7);  /* enable interrupts from board */
-		(void) inb_p(io+7);  /* and reset irq line */
-	} else {
-		/* polled mode -- 20 times per second */
-		/* this is really, really slow... should it poll more often? */
-		init_timer(&ltpc_timer);
-		ltpc_timer.function=ltpc_poll;
-		ltpc_timer.data = (unsigned long) dev;
-
-		ltpc_timer.expires = jiffies + 5;
-		add_timer(&ltpc_timer);
-		restore_flags(flags); 
-	}
-
-	return 0;
-}
-
-/* handles "ltpc=io,irq,dma" kernel command lines */
-static int __init ltpc_setup(char *str)
-{
-	int ints[5];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] == 0) {
-		if (str && !strncmp(str, "auto", 4)) {
-			/* do nothing :-) */
-		}
-		else {
-			/* usage message */
-			printk (KERN_ERR
-				"ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
-		}
-		return 1;
-	} else {
-		io = ints[1];
-		if (ints[0] > 1) {
-			irq = ints[2];
-			return 1;
-		}
-		if (ints[0] > 2) {
-			dma = ints[3];
-			return 1;
-		}
-		/* ignore any other paramters */
-	}
-	return 1;
-}
-
-__setup("ltpc=", ltpc_setup);
-
-#ifdef MODULE
-
-static char dev_name[8];
-
-static struct net_device dev_ltpc = {
-		dev_name, 
-		0, 0, 0, 0,
-	 	0x0, 0,
-	 	0, 0, 0, NULL, ltpc_probe };
-
-MODULE_PARM(debug, "i");
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(dma, "i");
-
-int init_module(void)
-{
-	int err, result;
-	
-        if(io == 0)
-		printk(KERN_NOTICE
-		       "ltpc: Autoprobing is not recommended for modules\n");
-
-	/* Find a name for this unit */
-	err=dev_alloc_name(&dev_ltpc,"lt%d");
-	
-	if(err<0)
-		return err;
-
-	if ((result = register_netdev(&dev_ltpc)) != 0) {
-		printk(KERN_DEBUG "could not register Localtalk-PC device\n");
-		return result;
-	} else {
-		if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n");
-		return 0;
-	}
-}
-
-void cleanup_module(void)
-{
-	long timeout;
-
-	ltpc_timer.data = 0;  /* signal the poll routine that we're done */
-
-	if(debug&DEBUG_VERBOSE) printk("freeing irq\n");
-
-	if(dev_ltpc.irq) {
-		free_irq(dev_ltpc.irq,&dev_ltpc);
-		dev_ltpc.irq = 0;
-	}
-
-	if(del_timer(&ltpc_timer)) 
-	{
-		/* either the poll was never started, or a poll is in process */
-		if(debug&DEBUG_VERBOSE) printk("waiting\n");
-		/* if it's in process, wait a bit for it to finish */
-		timeout = jiffies+HZ; 
-		add_timer(&ltpc_timer);
-		while(del_timer(&ltpc_timer) && time_after(timeout, jiffies))
-		{
-			add_timer(&ltpc_timer);
-			schedule();
-		}
-	}
-
-	if(debug&DEBUG_VERBOSE) printk("freeing dma\n");
-
-	if(dev_ltpc.dma) {
-		free_dma(dev_ltpc.dma);
-		dev_ltpc.dma = 0;
-	}
-
-	if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n");
-
-	if(dev_ltpc.base_addr) {
-		release_region(dev_ltpc.base_addr,8);
-		dev_ltpc.base_addr = 0;
-	}
-
-	if(debug&DEBUG_VERBOSE) printk("free_pages\n");
-
-	free_pages( (unsigned long) ltdmabuf, get_order(1000));
-	ltdmabuf=NULL;
-	ltdmacbuf=NULL;
-
-	if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n");
-
-	unregister_netdev(&dev_ltpc);
-
-	if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
-}
-#endif /* MODULE */
-
diff -u --recursive --new-file v2.3.49/linux/drivers/net/ltpc.h linux/drivers/net/ltpc.h
--- v2.3.49/linux/drivers/net/ltpc.h	Sun Feb  2 05:18:40 1997
+++ linux/drivers/net/ltpc.h	Wed Dec 31 16:00:00 1969
@@ -1,73 +0,0 @@
-/***   ltpc.h
- *
- *
- ***/
-
-#define LT_GETRESULT  0x00
-#define LT_WRITEMEM   0x01
-#define LT_READMEM    0x02
-#define LT_GETFLAGS   0x04
-#define LT_SETFLAGS   0x05
-#define LT_INIT       0x10
-#define LT_SENDLAP    0x13
-#define LT_RCVLAP     0x14
-
-/* the flag that we care about */
-#define LT_FLAG_ALLLAP 0x04
-
-struct lt_getresult {
-	unsigned char command;
-	unsigned char mailbox;
-};
-
-struct lt_mem {
-	unsigned char command;
-	unsigned char mailbox;
-	unsigned short addr;	/* host order */
-	unsigned short length;	/* host order */
-};
-
-struct lt_setflags {
-	unsigned char command;
-	unsigned char mailbox;
-	unsigned char flags;
-};
-
-struct lt_getflags {
-	unsigned char command;
-	unsigned char mailbox;
-};
-
-struct lt_init {
-	unsigned char command;
-	unsigned char mailbox;
-	unsigned char hint;
-};
-
-struct lt_sendlap {
-	unsigned char command;
-	unsigned char mailbox;
-	unsigned char dnode;
-	unsigned char laptype;
-	unsigned short length;	/* host order */
-};
-
-struct lt_rcvlap {
-	unsigned char command;
-	unsigned char dnode;
-	unsigned char snode;
-	unsigned char laptype;
-	unsigned short length;	/* host order */
-};
-
-union lt_command {
-	struct lt_getresult getresult;
-	struct lt_mem mem;
-	struct lt_setflags setflags;
-	struct lt_getflags getflags;
-	struct lt_init init;
-	struct lt_sendlap sendlap;
-	struct lt_rcvlap rcvlap;
-};
-typedef union lt_command lt_command;
-
diff -u --recursive --new-file v2.3.49/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c
--- v2.3.49/linux/drivers/net/ncr885e.c	Sun Feb 13 19:29:04 2000
+++ linux/drivers/net/ncr885e.c	Thu Mar  2 22:46:07 2000
@@ -1210,9 +1210,6 @@
 	unsigned short cmd;
 	unsigned char irq, latency;
 
-	if ( debug >= 0)
-		ncr885e_debug = debug;
-
 	while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, 
 					PCI_DEVICE_ID_NCR_53C885_ETHERNET,
 					pdev )) != NULL ) {
@@ -1399,9 +1396,6 @@
 int
 init_module(void)
 {
-	if ( debug >= 0)
-		ncr885e_debug = debug;
-
 	return ncr885e_probe();
 }
 
diff -u --recursive --new-file v2.3.49/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.3.49/linux/drivers/net/net_init.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/net_init.c	Fri Mar  3 12:54:45 2000
@@ -69,18 +69,24 @@
 static struct net_device *init_alloc_dev(int sizeof_priv)
 {
 	struct net_device *dev;
-	int alloc_size = sizeof(struct net_device) + IFNAMSIZ
-		+ sizeof_priv + 3;
-	alloc_size &= ~3;		/* Round to dword boundary. */
-	dev = (struct net_device *)kmalloc(alloc_size, GFP_KERNEL);
-	if(dev==NULL)
+	int alloc_size;
+	
+	/* 32-byte alignment */
+	alloc_size = sizeof (*dev) + IFNAMSIZ + sizeof_priv + 31;
+	alloc_size &= ~31;		
+
+	dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL);
+	if (dev == NULL)
 	{
 		printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n");
 		return NULL;
 	}
+
 	memset(dev, 0, alloc_size);
+
 	if (sizeof_priv)
 		dev->priv = (void *) (dev + 1);
+
 	dev->name = sizeof_priv + (char *)(dev + 1);
 	return dev;
 }
diff -u --recursive --new-file v2.3.49/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c
--- v2.3.49/linux/drivers/net/pcmcia/aironet4500_cs.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/pcmcia/aironet4500_cs.c	Mon Mar  6 15:53:44 2000
@@ -15,8 +15,7 @@
 
 
 #include <linux/module.h>
-//#include <pcmcia/config.h>
-
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
@@ -604,7 +603,7 @@
 
 
         
-int init_module(void)
+static int aironet_cs_init(void)
 {
 	servinfo_t serv;
 
@@ -621,7 +620,7 @@
 	return 0;
 }
 
-void cleanup_module(void)
+static void aironet_cs_exit(void)
 {
 	DEBUG(0, "awc_cs: unloading %c ",'\n');
 	unregister_pcmcia_driver(&dev_info);
@@ -636,4 +635,6 @@
 //		awc_detach(dev_list);
 }
 
-        
+module_init(aironet_cs_init);
+module_exit(aironet_cs_init);
+
diff -u --recursive --new-file v2.3.49/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in
--- v2.3.49/linux/drivers/net/tokenring/Config.in	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/tokenring/Config.in	Fri Mar  3 12:54:45 2000
@@ -3,7 +3,7 @@
 #
 
 mainmenu_option next_comment
-comment 'Token Ring driver support'
+comment 'Token Ring devices'
 
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" != "n" ]; then
diff -u --recursive --new-file v2.3.49/linux/drivers/net/tokenring/Makefile linux/drivers/net/tokenring/Makefile
--- v2.3.49/linux/drivers/net/tokenring/Makefile	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/tokenring/Makefile	Fri Mar  3 12:54:45 2000
@@ -5,73 +5,29 @@
 # removes any old dependencies. DON'T put your own dependencies here
 # unless it's something special (ie not a .c file).
 #
-# Note 2! The CFLAGS definition is now inherited from the
-# parent makefile.
-#
 
-#
-# Note : at this point, these files are compiled on all systems.
-# In the future, some of these should be built conditionally.
-#
-
-SUB_DIRS     := 
+SUB_DIRS     :=
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS)
 
+obj-y   :=
+obj-n   :=
+obj-m   :=
+obj-    :=
+export-objs :=
+
+obj-$(CONFIG_IBMTR) 	+= ibmtr.o
+obj-$(CONFIG_IBMOL) 	+= olympic.o
+obj-$(CONFIG_TMS380TR) 	+= tms380tr.o
+obj-$(CONFIG_ABYSS) 	+= abyss.o
+obj-$(CONFIG_MADGEMC) 	+= madgemc.o
+obj-$(CONFIG_TMSPCI) 	+= tmspci.o
+obj-$(CONFIG_SMCTR) 	+= smctr.o
 
 L_TARGET := tr.a
-L_OBJS   := 
-M_OBJS   :=
-
-ifeq ($(CONFIG_IBMTR),y)
-  L_OBJS += ibmtr.o
-else
-  ifeq ($(CONFIG_IBMTR),m)
-    M_OBJS += ibmtr.o
-  endif
-endif
-
-ifeq ($(CONFIG_IBMOL),y)
-  L_OBJS += olympic.o
-else
-  ifeq ($(CONFIG_IBMOL),m)
-    M_OBJS += olympic.o
-  endif
-endif
-
-ifeq ($(CONFIG_TMS380TR),y)
-  L_OBJS += tms380tr.o
-  ifeq ($(CONFIG_ABYSS),y)
-    L_OBJS += abyss.o
-  endif
- ifeq ($(CONFIG_MADGEMC),y)
-    L_OBJS += madgemc.o
-  endif
-  ifeq ($(CONFIG_TMSPCI),y)
-    L_OBJS += tmspci.o
-  endif
-else
-  ifeq ($(CONFIG_TMS380TR),m)
-    M_OBJS += tms380tr.o
-    ifeq ($(CONFIG_ABYSS),m)
-      M_OBJS += abyss.o
-    endif
-    ifeq ($(CONFIG_MADGEMC),m)
-      M_OBJS += madgemc.o
-    endif
-    ifeq ($(CONFIG_TMSPCI),m)
-      M_OBJS += tmspci.o
-    endif
-  endif
-endif
-
-ifeq ($(CONFIG_SMCTR),y)
-  L_OBJS += smctr.o
-else
-  ifeq ($(CONFIG_SMCTR),m)
-    M_OBJS += smctr.o
-  endif
-endif
+L_OBJS   := $(filter-out $(export-objs), $(obj-y))
+LX_OBJS  := $(filter     $(export-objs), $(obj-y))
+M_OBJS   := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS  := $(sort $(filter     $(export-objs), $(obj-m)))
 
 include $(TOPDIR)/Rules.make
-
diff -u --recursive --new-file v2.3.49/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.49/linux/drivers/net/via-rhine.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/net/via-rhine.c	Fri Mar  3 12:54:45 2000
@@ -17,10 +17,21 @@
 
 	Support and updates available at
 	http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html
+
+
+	Linux kernel version history:
+	
+	LK1.1.0:
+	- Jeff Garzik: softnet 'n stuff
+	
+	LK1.1.1:
+	- Justin Guyett: softnet and locking fixes
+	- Jeff Garzik: use PCI interface
+		
 */
 
 static const char *versionA =
-"via-rhine.c:v1.01 2/27/99  Written by Donald Becker\n";
+"via-rhine.c:v1.01-LK1.1.1  3/2/2000  Written by Donald Becker\n";
 static const char *versionB =
 "  http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
 
@@ -29,7 +40,6 @@
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
@@ -112,7 +122,6 @@
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
@@ -157,7 +166,7 @@
 a fresh skbuff is allocated and the frame is copied to the new skbuff.
 When the incoming frame is larger, the skbuff is passed directly up the
 protocol stack.  Buffers consumed this way are replaced by newly allocated
-skbuffs in the last phase of netdev_rx().
+skbuffs in the last phase of via_rhine_rx().
 
 The RX_COPYBREAK value is chosen to trade-off the memory wasted by
 using a full-sized skbuff for small frames vs. the copying costs of larger
@@ -208,34 +217,50 @@
 
 */
 
-
+
 
 /* This table drives the PCI probe routines.  It's mostly boilerplate in all
    of the drivers, and will likely be provided by some future kernel.
    Note the matching code -- the first table entry matchs all 56** cards but
    second only the 1234 card.
 */
+
 enum pci_flags_bit {
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
-struct pci_id_info {
+
+enum via_rhine_chips {
+	vt86c100a = 0,
+	vt3043,
+};
+
+struct via_rhine_chip_info {
 	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
+	u16 flags;
 	int io_size;
-	struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt);
 };
 
-static struct net_device *via_probe1(struct pci_dev *pdev, long ioaddr, int irq,
-								 int chp_idx, int fnd_cnt);
 
-static struct pci_id_info pci_tbl[] = {
-	{ "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
-	  PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
-	{ "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff,
-	  PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
-	{0,},						/* 0 terminated list. */
+/* directly indexed by enum via_rhine_chips, above */
+static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata =
+{
+	{"VIA VT86C100A Rhine-II",
+	 PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
+	 128,},
+	{"VIA VT3043 Rhine",
+	 PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
+	 128,},
+};
+
+static struct pci_device_id via_rhine_pci_tbl[] __devinitdata =
+{
+	{0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a},
+	{0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043},
+	{0,},			/* terminate list */
 };
+MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl);
+
 
 
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
@@ -315,16 +340,14 @@
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	unsigned char *tx_buf[TX_RING_SIZE];	/* Tx bounce buffers */
 	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
-	struct net_device *next_module;			/* Link for devices of this type. */
 	struct net_device_stats stats;
 	struct timer_list timer;	/* Media monitoring timer. */
 	spinlock_t lock;
 	/* Frequently used values: keep some adjacent for cache effect. */
 	int chip_id;
-	long in_interrupt;			/* Word-long for SMP locks. */
 	struct rx_desc *rx_head_desc;
-	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
-	unsigned int cur_tx, dirty_tx;
+	unsigned short int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned short int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
 	u16 chip_cmd;						/* Current setting for ChipCmd */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
@@ -342,136 +365,94 @@
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static int  netdev_open(struct net_device *dev);
-static void check_duplex(struct net_device *dev);
-static void netdev_timer(unsigned long data);
-static void tx_timeout(struct net_device *dev);
-static void init_ring(struct net_device *dev);
-static int  start_tx(struct sk_buff *skb, struct net_device *dev);
-static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
-static int  netdev_rx(struct net_device *dev);
-static void netdev_error(struct net_device *dev, int intr_status);
-static void set_rx_mode(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
+static int  via_rhine_open(struct net_device *dev);
+static void via_rhine_check_duplex(struct net_device *dev);
+static void via_rhine_timer(unsigned long data);
+static void via_rhine_tx_timeout(struct net_device *dev);
+static void via_rhine_init_ring(struct net_device *dev);
+static int  via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
+static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void via_rhine_tx(struct net_device *dev);
+static void via_rhine_rx(struct net_device *dev);
+static void via_rhine_error(struct net_device *dev, int intr_status);
+static void via_rhine_set_rx_mode(struct net_device *dev);
+static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int  netdev_close(struct net_device *dev);
-
-
+static int  via_rhine_close(struct net_device *dev);
 
-/* A list of our installed devices, for removing the driver module. */
-static struct net_device *root_net_dev = NULL;
 
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   cards we know about in slot order. */
-
-static int pci_etherdev_probe(struct pci_id_info pci_tbl[])
+static int __devinit via_rhine_init_one (struct pci_dev *pdev,
+					 const struct pci_device_id *ent)
 {
-	int cards_found = 0;
-	int pci_index = 0;
-	unsigned char pci_bus, pci_device_fn;
 	struct net_device *dev;
+	struct netdev_private *np;
+	int i, option;
+	int chip_id = (int) ent->driver_data;
+	int irq = pdev->irq;
+	static int card_idx = -1;
+	static int did_version = 0;
+	long ioaddr;
+	int io_size;
+	
+	/* print version once and once only */
+	if (! did_version++) {
+		printk (KERN_INFO "%s", versionA);
+		printk (KERN_INFO "%s", versionB);
+	}
+	
+	card_idx++;
+	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+	io_size = via_rhine_chip_info[chip_id].io_size;
 
-	for (;pci_index < 0xff; pci_index++) {
-		u16 vendor, device, pci_command, new_command;
-		int chip_idx, irq;
-		long pciaddr;
-		long ioaddr;
-		struct pci_dev *pdev;
-
-		if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-								&pci_bus, &pci_device_fn)
-			!= PCIBIOS_SUCCESSFUL)
-			break;
-		
-		pdev = pci_find_slot (pci_bus, pci_device_fn);
-		if (!pdev) continue;
-		vendor = pdev->vendor;
-		device = pdev->device;
-
-		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-			if (vendor == pci_tbl[chip_idx].vendor_id
-				&& (device & pci_tbl[chip_idx].device_id_mask) ==
-				pci_tbl[chip_idx].device_id)
-				break;
-		if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
-			continue;
 
 #ifdef VIA_USE_IO
-		pciaddr = pdev->resource[0].start;
+	ioaddr = pci_resource_start (pdev, 0);
 #else
-		pciaddr = pdev->resource[1].start;
+	ioaddr = pci_resource_start (pdev, 1);
 #endif
-		irq = pdev->irq;
-
-		if (debug > 2)
-			printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
-				   pci_tbl[chip_idx].name, pciaddr, irq);
-
-		if (pci_tbl[chip_idx].flags & PCI_USES_IO) {
-			ioaddr = pciaddr & ~3;
-			if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-				continue;
-		} else if ((ioaddr = (long)ioremap(pciaddr & ~0xf,
-										 pci_tbl[chip_idx].io_size)) == 0) {
-			printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-				   pciaddr);
-			continue;
-		}
-
-		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-		new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled the"
-				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
-				   pdev->bus->number, pdev->devfn, pci_command, new_command);
-			pci_write_config_word(pdev, PCI_COMMAND, new_command);
-		}
-
-		dev = pci_tbl[chip_idx].probe1(pdev, ioaddr, irq, chip_idx, cards_found);
 
-		if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-			u8 pci_latency;
-			pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < min_pci_latency) {
-				printk(KERN_INFO "  PCI latency timer (CFLT) is "
-					   "unreasonably low at %d.  Setting to %d clocks.\n",
-					   pci_latency, min_pci_latency);
-				pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
-			}
-		}
-		dev = 0;
-		cards_found++;
+	if (pci_enable_device (pdev)) {
+		printk (KERN_ERR "unable to init PCI device (card #%d)\n",
+			card_idx);
+		goto err_out;
 	}
+	
+	if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER)
+		pci_set_master (pdev);
 
-	return cards_found ? 0 : -ENODEV;
-}
-
-
-static struct net_device *via_probe1(struct pci_dev *pdev,
-					 long ioaddr, int irq,
-					 int chip_id, int card_idx)
-{
-	struct net_device *dev;
-	struct netdev_private *np;
-	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-
-	dev = init_etherdev(NULL, 0);
-	if(dev==NULL)
-		return NULL;
-
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
-		   dev->name, pci_tbl[chip_id].name, ioaddr);
-
-#ifdef VIA_USE_IO
-	if (!request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name)) {
-		unregister_netdev (dev);
-		kfree (dev);
-		return NULL;
+	dev = init_etherdev(NULL, sizeof (*np));
+	if (dev == NULL) {
+		printk (KERN_ERR "init_ethernet failed for card #%d\n",
+			card_idx);
+		goto err_out;
+	}
+	
+	if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) {
+		printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n",
+			dev->name, io_size,
+			pci_resource_start (pdev, 0));
+		goto err_out_free_netdev;
+	}
+	if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) {
+		printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n",
+			dev->name, io_size,
+			pci_resource_start (pdev, 1));
+		goto err_out_free_pio;
+	}
+
+#ifndef VIA_USE_IO
+	ioaddr = (long) ioremap (ioaddr, io_size);
+	if (!ioaddr) {
+		printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n",
+			dev->name, io_size,
+			pci_resource_start (pdev, 1));
+		goto err_out_free_mmio;
 	}
 #endif
 
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, via_rhine_chip_info[chip_id].name, ioaddr);
+
 	/* Ideally we would be read the EEPROM but access may be locked. */
 	for (i = 0; i <6; i++)
 		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
@@ -485,16 +466,8 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	/* Make certain the descriptor lists are cache-aligned. */
-	np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31);
-	/* FIXME! check return !!! */		
-	memset(np, 0, sizeof(*np));
-	dev->priv = np;
-
-	np->next_module = root_net_dev;
-	root_net_dev = dev;
-
-	np->lock = SPIN_LOCK_UNLOCKED;
+	np = dev->priv;
+	spin_lock_init (&np->lock);
 	np->chip_id = chip_id;
 
 	if (dev->mem_start)
@@ -515,14 +488,16 @@
 		np->duplex_lock = 1;
 
 	/* The chip-specific entries in the device structure. */
-	dev->open = &netdev_open;
-	dev->hard_start_xmit = &start_tx;
-	dev->stop = &netdev_close;
-	dev->get_stats = &get_stats;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
-	dev->tx_timeout = tx_timeout;
+	dev->open = via_rhine_open;
+	dev->hard_start_xmit = via_rhine_start_tx;
+	dev->stop = via_rhine_close;
+	dev->get_stats = via_rhine_get_stats;
+	dev->set_multicast_list = via_rhine_set_rx_mode;
+	dev->do_ioctl = mii_ioctl;
+	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	
+	pdev->driver_data = dev;
 
 	if (cap_tbl[np->chip_id].flags & CanHaveMII) {
 		int phy, phy_idx = 0;
@@ -541,10 +516,25 @@
 		np->mii_cnt = phy_idx;
 	}
 
-	return dev;
+	return 0;
+
+#ifndef VIA_USE_IO
+/* note this is ifdef'd because the ioremap is ifdef'd...
+ * so additional exit conditions above this must move
+ * release_mem_region outside of the ifdef */
+err_out_free_mmio:
+	release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name));
+#endif
+err_out_free_pio:
+	release_region(pci_resource_start (pdev, 0), io_size);
+err_out_free_netdev:
+	unregister_netdev (dev);
+	kfree (dev);
+err_out:
+	return -ENODEV;
 }
 
-
+
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
 
 static int mdio_read(struct net_device *dev, int phy_id, int regnum)
@@ -581,8 +571,8 @@
 	return;
 }
 
-
-static int netdev_open(struct net_device *dev)
+
+static int via_rhine_open(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -591,16 +581,16 @@
 	/* Reset the chip. */
 	writew(CmdReset, ioaddr + ChipCmd);
 
-	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
+	if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev))
 		return -EAGAIN;
 
 	if (debug > 1)
-		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+		printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
 			   dev->name, dev->irq);
 
 	MOD_INC_USE_COUNT;
 
-	init_ring(dev);
+	via_rhine_init_ring(dev);
 
 	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
 	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
@@ -613,15 +603,14 @@
 	/* Configure the FIFO thresholds. */
 	writeb(0x20, ioaddr + TxConfig);	/* Initial threshold 32 bytes */
 	np->tx_thresh = 0x20;
-	np->rx_thresh = 0x60;				/* Written in set_rx_mode(). */
+	np->rx_thresh = 0x60;				/* Written in via_rhine_set_rx_mode(). */
 
 	if (dev->if_port == 0)
 		dev->if_port = np->default_port;
 
 	netif_start_queue(dev);
-	np->in_interrupt = 0;
 
-	set_rx_mode(dev);
+	via_rhine_set_rx_mode(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
 	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
@@ -634,10 +623,10 @@
 		np->chip_cmd |= CmdFDuplex;
 	writew(np->chip_cmd, ioaddr + ChipCmd);
 
-	check_duplex(dev);
+	via_rhine_check_duplex(dev);
 
 	if (debug > 2)
-		printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
+		printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
 			   "MII status: %4.4x.\n",
 			   dev->name, readw(ioaddr + ChipCmd),
 			   mdio_read(dev, np->phys[0], 1));
@@ -646,22 +635,23 @@
 	init_timer(&np->timer);
 	np->timer.expires = RUN_AT(1);
 	np->timer.data = (unsigned long)dev;
-	np->timer.function = &netdev_timer;				/* timer handler */
+	np->timer.function = &via_rhine_timer;				/* timer handler */
 	add_timer(&np->timer);
 
 	return 0;
 }
 
-static void check_duplex(struct net_device *dev)
+static void via_rhine_check_duplex(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+	int negotiated = mii_reg5 & np->advertising;
 	int duplex;
 
 	if (np->duplex_lock  ||  mii_reg5 == 0xffff)
 		return;
-	duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 	if (np->full_duplex != duplex) {
 		np->full_duplex = duplex;
 		if (debug)
@@ -676,7 +666,7 @@
 	}
 }
 
-static void netdev_timer(unsigned long data)
+static void via_rhine_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -687,41 +677,41 @@
 		printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
 	}
-	check_duplex(dev);
+	via_rhine_check_duplex(dev);
 
 	np->timer.expires = RUN_AT(next_tick);
 	add_timer(&np->timer);
 }
 
-static void tx_timeout(struct net_device *dev)
+static void via_rhine_tx_timeout (struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = (struct netdev_private *) dev->priv;
 	long ioaddr = dev->base_addr;
 
-	printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
-		   "%4.4x, resetting...\n",
-		   dev->name, readw(ioaddr + IntrStatus),
-		   mdio_read(dev, np->phys[0], 1));
-
-  /* Perhaps we should reinitialize the hardware here. */
-  dev->if_port = 0;
-  /* Stop and restart the chip's Tx processes . */
-
-  /* Trigger an immediate transmit demand. */
-
-  dev->trans_start = jiffies;
-  np->stats.tx_errors++;
-  return;
+	printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
+		"%4.4x, resetting...\n",
+		dev->name, readw (ioaddr + IntrStatus),
+		mdio_read (dev, np->phys[0], 1));
+
+	/* Perhaps we should reinitialize the hardware here. */
+	dev->if_port = 0;
+	/* Stop and restart the chip's Tx processes . */
+
+	/* Trigger an immediate transmit demand. */
+
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+
+	netif_start_queue (dev);
 }
 
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void init_ring(struct net_device *dev)
+static void via_rhine_init_ring(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	int i;
 
-	np->tx_full = 0;
 	np->cur_rx = np->cur_tx = 0;
 	np->dirty_rx = np->dirty_tx = 0;
 
@@ -749,7 +739,6 @@
 		np->rx_ring[i].rx_status = 0;
 		np->rx_ring[i].rx_length = DescOwn;
 	}
-	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = 0;
@@ -763,14 +752,18 @@
 	return;
 }
 
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
+static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	unsigned entry;
+	unsigned long flags;
 
 	/* Caution: the write order is important here, set the field
 	   with the "ownership" bits last. */
 
+	/* lock eth irq */
+	spin_lock_irqsave (&np->lock, flags);
+
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 
@@ -796,12 +789,13 @@
 	/* Wake the potentially-idle transmit channel. */
 	writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 
-	if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1)
-		netif_start_queue(dev);		/* Typical path */
-	else
-		np->tx_full = 1;
+	if (np->cur_tx == np->dirty_tx + TX_RING_SIZE)
+		netif_stop_queue(dev);
+
 	dev->trans_start = jiffies;
 
+	spin_unlock_irqrestore (&np->lock, flags);
+
 	if (debug > 4) {
 		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
 			   dev->name, np->cur_tx, entry);
@@ -811,20 +805,15 @@
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
-	struct netdev_private *np;
 	long ioaddr, boguscnt = max_interrupt_work;
+	u32 intr_status;
 
 	ioaddr = dev->base_addr;
-	np = (struct netdev_private *)dev->priv;
 	
-	spin_lock (&np->lock);
-
-	do {
-		u32 intr_status = readw(ioaddr + IntrStatus);
-
+	while ((intr_status = readw(ioaddr + IntrStatus))) {
 		/* Acknowledge all of the current interrupt sources ASAP. */
 		writew(intr_status & 0xffff, ioaddr + IntrStatus);
 
@@ -832,54 +821,18 @@
 			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
 				   dev->name, intr_status);
 
-		if (intr_status == 0)
-			break;
-
 		if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
 						   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
-			netdev_rx(dev);
+			via_rhine_rx(dev);
 
-		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-			int entry = np->dirty_tx % TX_RING_SIZE;
-			int txstatus;
-			if (np->tx_ring[entry].tx_own)
-				break;
-			txstatus = np->tx_ring[entry].tx_status;
-			if (debug > 6)
-				printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
-					   entry, txstatus);
-			if (txstatus & 0x8000) {
-				if (debug > 1)
-					printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
-						   dev->name, txstatus);
-				np->stats.tx_errors++;
-				if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
-				if (txstatus & 0x0200) np->stats.tx_window_errors++;
-				if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
-				if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
-				if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
-				/* Transmitter restarted in 'abnormal' handler. */
-			} else {
-				np->stats.collisions += (txstatus >> 3) & 15;
-				np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
-				np->stats.tx_packets++;
-			}
-			/* Free the original skb. */
-			dev_kfree_skb_irq(np->tx_skbuff[entry]);
-			np->tx_skbuff[entry] = 0;
-		}
-		if (np->tx_full &&
-		    netif_queue_stopped(dev) &&
-		    np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
-			/* The ring is no longer full, clear tbusy. */
-			np->tx_full = 0;
-			netif_wake_queue (dev);
-		}
+		if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+						   IntrTxAborted))
+			via_rhine_tx(dev);
 
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |
 						   IntrStatsMax | IntrTxAbort | IntrTxUnderrun))
-			netdev_error(dev, intr_status);
+			via_rhine_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
 			printk(KERN_WARNING "%s: Too much work at interrupt, "
@@ -887,25 +840,67 @@
 				   dev->name, intr_status);
 			break;
 		}
-	} while (1);
+	}
 
 	if (debug > 3)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
+}
+
+/* This routine is logically part of the interrupt handler, but isolated
+   for clarity and better register allocation. */
+static void via_rhine_tx(struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE;
+
+	spin_lock (&np->lock);
+
+	/* if tx_full is set, they're all dirty, not clean */
+	while (np->dirty_tx != np->cur_tx) {
+		if (np->tx_ring[entry].tx_own) /* transmit request pending */
+			break;
+		txstatus = np->tx_ring[entry].tx_status;
+		if (debug > 6)
+			printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
+				   entry, txstatus);
+		if (txstatus & 0x8000) {
+			if (debug > 1)
+				printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
+					   dev->name, txstatus);
+			np->stats.tx_errors++;
+			if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
+			if (txstatus & 0x0200) np->stats.tx_window_errors++;
+			if (txstatus & 0x0100) np->stats.tx_aborted_errors++;
+			if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;
+			if (txstatus & 0x0002) np->stats.tx_fifo_errors++;
+			/* Transmitter restarted in 'abnormal' handler. */
+		} else {
+			np->stats.collisions += (txstatus >> 3) & 15;
+			np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
+			np->stats.tx_packets++;
+        	}
+        	/* Free the original skb. */
+        	dev_kfree_skb_irq(np->tx_skbuff[entry]);
+        	np->tx_skbuff[entry] = NULL;
+		entry = (++np->dirty_tx) % TX_RING_SIZE;
+	}
+	if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2)
+		netif_wake_queue (dev);
 
 	spin_unlock (&np->lock);
 }
 
 /* This routine is logically part of the interrupt handler, but isolated
    for clarity and better register allocation. */
-static int netdev_rx(struct net_device *dev)
+static void via_rhine_rx(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
-	int entry = np->cur_rx % RX_RING_SIZE;
-	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+	int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE;
+	int boguscnt = RX_RING_SIZE;
 
 	if (debug > 4) {
-		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
+		printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n",
 			   entry, np->rx_head_desc->rx_length);
 	}
 
@@ -916,7 +911,7 @@
 		u16 desc_status = desc->rx_status;
 
 		if (debug > 4)
-			printk(KERN_DEBUG "  netdev_rx() status is %4.4x.\n",
+			printk(KERN_DEBUG "  via_rhine_rx() status is %4.4x.\n",
 				   desc_status);
 		if (--boguscnt < 0)
 			break;
@@ -924,15 +919,15 @@
 			if ((desc_status & RxWholePkt) !=  RxWholePkt) {
 				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
 					   "multiple buffers, entry %#x length %d status %4.4x!\n",
-					   dev->name, np->cur_rx, data_size, desc_status);
+					   dev->name, entry, data_size, desc_status);
 				printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
 					   dev->name, np->rx_head_desc,
-					   &np->rx_ring[np->cur_rx % RX_RING_SIZE]);
+					   &np->rx_ring[entry]);
 				np->stats.rx_length_errors++;
 			} else if (desc_status & RxErr) {
 				/* There was a error. */
 				if (debug > 2)
-					printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
+					printk(KERN_DEBUG "  via_rhine_rx() Rx error was %8.8x.\n",
 						   desc_status);
 				np->stats.rx_errors++;
 				if (desc_status & 0x0030) np->stats.rx_length_errors++;
@@ -973,9 +968,9 @@
 	}
 
 	/* Refill the Rx ring buffers. */
-	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+	while (np->dirty_rx != np->cur_rx) {
 		struct sk_buff *skb;
-		entry = np->dirty_rx % RX_RING_SIZE;
+		entry = np->dirty_rx++ % RX_RING_SIZE;
 		if (np->rx_skbuff[entry] == NULL) {
 			skb = dev_alloc_skb(np->rx_buf_sz);
 			np->rx_skbuff[entry] = skb;
@@ -990,10 +985,9 @@
 
 	/* Pre-emptively restart Rx engine. */
 	writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
-	return 0;
 }
 
-static void netdev_error(struct net_device *dev, int intr_status)
+static void via_rhine_error(struct net_device *dev, int intr_status)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -1003,7 +997,7 @@
 			/* Link failed, restart autonegotiation. */
 			mdio_write(dev, np->phys[0], 0, 0x3300);
 		else
-			check_duplex(dev);
+			via_rhine_check_duplex(dev);
 		if (debug)
 			printk(KERN_ERR "%s: MII status changed: Autonegotiation "
 				   "advertising %4.4x  partner %4.4x.\n", dev->name,
@@ -1026,7 +1020,7 @@
 			printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
 				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
 	}
-	if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) {
+	if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) {
 		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 			   dev->name, intr_status);
 		/* Recovery for other fault sources not known. */
@@ -1034,7 +1028,7 @@
 	}
 }
 
-static struct enet_statistics *get_stats(struct net_device *dev)
+static struct net_device_stats *via_rhine_get_stats(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -1068,7 +1062,7 @@
     return crc;
 }
 
-static void set_rx_mode(struct net_device *dev)
+static void via_rhine_set_rx_mode(struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -1120,7 +1114,7 @@
 	}
 }
 
-static int netdev_close(struct net_device *dev)
+static int via_rhine_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -1162,45 +1156,49 @@
 	return 0;
 }
 
-static int __init via_rhine_init_module (void)
+
+static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
 {
-	if (debug)					/* Emit version even if no cards detected. */
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-#ifdef CARDBUS
-	register_driver(&etherdev_ops);
-	return 0;
-#else
-	return pci_etherdev_probe(pci_tbl);
+	struct net_device *dev = pdev->driver_data;
+	struct netdev_private *np = (struct netdev_private *)(dev->priv);
+	
+	unregister_netdev(dev);
+
+	release_region(pci_resource_start (pdev, 0),
+		       via_rhine_chip_info[np->chip_id].io_size);
+	release_mem_region(pci_resource_start (pdev, 1),
+		           via_rhine_chip_info[np->chip_id].io_size);
+
+#ifndef VIA_USE_IO
+	iounmap((char *)(dev->base_addr));
 #endif
+
+	kfree(dev);
 }
 
-static void __exit via_rhine_cleanup_module (void)
+
+static struct pci_driver via_rhine_driver = {
+	name:		"via-rhine",
+	id_table:	via_rhine_pci_tbl,
+	probe:		via_rhine_init_one,
+	remove:		via_rhine_remove_one,
+};
+
+
+static int __init via_rhine_init (void)
 {
+	return pci_module_init (&via_rhine_driver);
+}
 
-#ifdef CARDBUS
-	unregister_driver(&etherdev_ops);
-#endif
 
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_net_dev) {
-		struct netdev_private *np =
-			(struct netdev_private *)(root_net_dev->priv);
-		unregister_netdev(root_net_dev);
-#ifdef VIA_USE_IO
-		release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size);
-#else
-		iounmap((char *)(root_net_dev->base_addr));
-#endif
-		kfree(root_net_dev);
-		root_net_dev = np->next_module;
-#if 0
-		kfree(np);				/* Assumption: no struct realignment. */
-#endif
-	}
+static void __exit via_rhine_cleanup (void)
+{
+	pci_unregister_driver (&via_rhine_driver);
 }
 
-module_init(via_rhine_init_module);
-module_exit(via_rhine_cleanup_module);
+
+module_init(via_rhine_init);
+module_exit(via_rhine_cleanup);
 
 
 /*
diff -u --recursive --new-file v2.3.49/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.3.49/linux/drivers/net/yellowfin.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/net/yellowfin.c	Fri Mar  3 12:54:45 2000
@@ -1263,7 +1263,7 @@
 	real_ioaddr = ioaddr = pci_resource_start (pdev, 0);
 #else
 	real_ioaddr = ioaddr = pci_resource_start (pdev, 1);
-	ioaddr = ioremap(ioaddr, YELLOWFIN_SIZE);
+	ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);
 #endif
 	irq = pdev->irq;
 
diff -u --recursive --new-file v2.3.49/linux/drivers/parport/Config.in linux/drivers/parport/Config.in
--- v2.3.49/linux/drivers/parport/Config.in	Fri Jan 21 18:19:16 2000
+++ linux/drivers/parport/Config.in	Fri Mar  3 12:49:08 2000
@@ -5,6 +5,9 @@
 # Parport configuration.
 #
 
+mainmenu_option next_comment
+comment 'Parallel port support'
+
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
    dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
@@ -47,3 +50,5 @@
 
    bool '  IEEE 1284 transfer modes' CONFIG_PARPORT_1284
 fi
+
+endmenu
diff -u --recursive --new-file v2.3.49/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.49/linux/drivers/parport/parport_pc.c	Thu Mar  2 14:36:22 2000
+++ linux/drivers/parport/parport_pc.c	Fri Mar  3 12:54:45 2000
@@ -70,20 +70,40 @@
 #define ECR_TST 06
 #define ECR_CNF 07
 
+#undef DEBUG
+
+#ifdef DEBUG
+#define DPRINTK  printk
+#else
+#define DPRINTK(stuff...)
+#endif
+
+
+#define NR_SUPERIOS 3
+static struct superio_struct {	/* For Super-IO chips autodetection */
+	int io;
+	int irq;
+	int dma;
+} superios[NR_SUPERIOS]= { {0,},};
+	
 /* frob_control, but for ECR */
 static void frob_econtrol (struct parport *pb, unsigned char m,
 			   unsigned char v)
 {
 	unsigned char ectr = inb (ECONTROL (pb));
-#ifdef DEBUG_PARPORT
-	printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
+	DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
 		m, v, ectr, (ectr & ~m) ^ v);
-#endif
+
 	outb ((ectr & ~m) ^ v, ECONTROL (pb));
 }
 
 #ifdef CONFIG_PARPORT_PC_FIFO
-/* Safely change the mode bits in the ECR */
+/* Safely change the mode bits in the ECR 
+   Returns:
+	    0    : Success
+	   -EBUSY: Could not drain FIFO in some finite amount of time,
+		   mode not changed!
+ */
 static int change_mode(struct parport *p, int m)
 {
 	const struct parport_pc_private *priv = p->physport->private_data;
@@ -91,6 +111,8 @@
 	unsigned char oecr;
 	int mode;
 
+	DPRINTK("parport change_mode ECP-ISA to mode 0x%02x\n",m);
+
 	if (!priv->ecr) {
 		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
 		return 0;
@@ -993,6 +1015,305 @@
 	parport_ieee1284_read_byte,
 };
 
+/* Super-IO chipset detection, Winbond, SMSC */
+
+static void show_parconfig_smsc37c669(int io, int key)
+{
+	int cr1,cr4,cra,cr23,cr26,cr27,i=0;
+	char *modes[]={ "SPP and Bidirectional (PS/2)",	
+			"EPP and SPP",
+			"ECP",
+			"ECP and EPP"};
+
+	outb(key,io);
+	outb(key,io);
+	outb(1,io);
+	cr1=inb(io+1);
+	outb(4,io);
+	cr4=inb(io+1);
+	outb(0x0a,io);
+	cra=inb(io+1);
+	outb(0x23,io);
+	cr23=inb(io+1);
+	outb(0x26,io);
+	cr26=inb(io+1);
+	outb(0x27,io);
+	cr27=inb(io+1);
+	outb(0xaa,io);
+
+	printk ("SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, "
+		"A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n",
+		cr1,cr4,cra,cr23,cr26,cr27);
+
+	/* The documentation calls DMA and IRQ-Lines by letters, so
+	   the board maker can/will wire them
+	   appropriately/randomly...  G=reserved H=IDE-irq, */
+	printk ("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, "
+		"fifo threshold=%d\n", cr23*4,
+		(cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-',
+		(cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f);
+	printk("SMSC LPT Config: enabled=%s power=%s\n",
+	       (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no");
+	printk("SMSC LPT Config: Port mode=%s, EPP version =%s\n",
+	       (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], 
+	       (cr4 & 40) ? "1.7" : "1.9");
+
+	/* Heuristics !  BIOS setup for this mainboard device limits
+	   the choices to standard settings, i.e. io-address and IRQ
+	   are related, however DMA can be 1 or 3, assume DMA_A=DMA1,
+	   DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */
+	if(cr23*4 >=0x100) { /* if active */
+		while((superios[i].io!= 0) && (i<NR_SUPERIOS))
+			i++;
+		if(i==NR_SUPERIOS)
+			printk("Super-IO: too many chips!\n");
+		else {
+			int d;
+			switch (cr23*4) {
+				case 0x3bc:
+					superios[i].io = 0x3bc;
+					superios[i].irq = 7;
+					break;
+				case 0x378:
+					superios[i].io = 0x378;
+					superios[i].irq = 7;
+					break;
+				case 0x278:
+					superios[i].io = 0x278;
+					superios[i].irq = 5;
+			}
+			d=(cr26 &0x0f);
+			if((d==1) || (d==3)) 
+				superios[i].dma= d;
+			else
+				superios[i].dma= PARPORT_DMA_NONE;
+		}
+ 	}
+}
+
+
+static void show_parconfig_winbond(int io, int key)
+{
+	int cr30,cr60,cr61,cr70,cr74,crf0,i=0;
+	char *modes[]={ "Standard (SPP) and Bidirectional(PS/2)", /* 0 */
+			"EPP-1.9 and SPP",
+			"ECP",
+			"ECP and EPP-1.9",
+			"Standard (SPP)",
+			"EPP-1.7 and SPP",		/* 5 */
+			"undefined!",
+			"ECP and EPP-1.7"};
+	char *irqtypes[]={"pulsed low, high-Z", "follows nACK"};
+		
+	/* The registers are called compatible-PnP because the
+           register layout is modelled after ISA-PnP, the access
+           method is just another ... */
+	outb(key,io);
+	outb(key,io);
+	outb(0x07,io);   /* Register 7: Select Logical Device */
+	outb(0x01,io+1); /* LD1 is Parallel Port */
+	outb(0x30,io);
+	cr30=inb(io+1);
+	outb(0x60,io);
+	cr60=inb(io+1);
+	outb(0x61,io);
+	cr61=inb(io+1);
+	outb(0x70,io);
+	cr70=inb(io+1);
+	outb(0x74,io);
+	cr74=inb(io+1);
+	outb(0xf0,io);
+	crf0=inb(io+1);
+	outb(0xaa,io);
+
+	printk("Winbond LPT Config: cr_30=%02x 60,61=%02x%02x "
+	       "70=%02x 74=%02x, f0=%02x\n", cr30,cr60,cr61,cr70,cr74,crf0);
+	printk("Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", 
+	       (cr30 & 0x01) ? "yes":"no", cr60,cr61,cr70&0x0f );
+	if ((cr74 & 0x07) > 3)
+		printk("dma=none\n");
+	else
+		printk("dma=%d\n",cr74 & 0x07);
+	printk("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n",
+	       irqtypes[crf0>>7], (crf0>>3)&0x0f);
+	printk("Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]);
+
+	if(cr30 & 0x01) { /* the settings can be interrogated later ... */
+		while((superios[i].io!= 0) && (i<NR_SUPERIOS))
+			i++;
+		if(i==NR_SUPERIOS) 
+			printk("Super-IO: too many chips!\n");
+		else {
+			superios[i].io = (cr60<<8)|cr61;
+			superios[i].irq = cr70&0x0f;
+			superios[i].dma = (((cr74 & 0x07) > 3) ?
+					   PARPORT_DMA_NONE : (cr74 & 0x07));
+		}
+	}
+}
+
+static void decode_winbond(int efer, int key, int devid, int devrev, int oldid)
+{
+	char *type=NULL;
+	int id,progif=2;
+
+	if (devid == devrev)
+		/* simple heuristics, we happened to read some
+                   non-winbond register */
+		return;
+
+	printk("Winbond chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x "
+	       "oldid=%02x\n", efer,key,devid,devrev,oldid);
+	id=(devid<<8) | devrev;
+
+	/* Values are from public data sheets pdf files, I can just
+           confirm 83977TF is correct :-) */
+	if      (id == 0x9773) type="83977TF";
+	else if (id == 0x9774) type="83977ATF";
+	else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x";
+	else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97x35x";
+	else if ((id & ~0x0f) == 0x5210) type="83627";
+	else if ((id & ~0x0f) == 0x6010) type="83697HF";
+	else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;}
+	else if ((oldid &0x0f ) == 0x0c) { type="83877ATF"; progif=1;}
+	else progif=0;
+
+	if(type==NULL) 
+		printk("Winbond unkown chip type\n");
+	else	
+	 	printk("Winbond chip type %s\n",type);
+
+	if(progif==2)
+		show_parconfig_winbond(efer,key);
+	return;
+}
+
+static void decode_smsc(int efer, int key, int devid, int devrev)
+{
+        char *type=NULL;
+	void (*func)(int io, int key);
+        int id;
+
+        if (devid == devrev)
+		/* simple heuristics, we happened to read some
+                   non-winbond register */
+		return;
+
+	func=NULL;
+        printk("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x\n",
+	       efer,key,devid,devrev);
+        id=(devid<<8) | devrev;
+
+	if	(id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;}
+	else if	(id==0x6582) type="37c665IR";
+	else if	((id==0x6502) && (key==0x44)) type="37c665GT";
+	else if	((id==0x6502) && (key==0x55)) type="37c666GT";
+
+	if(type==NULL)
+                printk("SMSC unknown chip type\n");
+        else
+                printk("SMSC chip type %s\n",type);
+
+	if(func) (func)(efer,key);
+	return;
+}
+
+
+static void winbond_check(int io, int key)
+{
+	int devid,devrev,oldid;
+
+	outb(key,io);
+	outb(key,io);     /* Write Magic Sequence to EFER, extended
+                             funtion enable register */
+	outb(0x20,io);    /* Write EFIR, extended function index register */
+	devid=inb(io+1);  /* Read EFDR, extended function data register */
+	outb(0x21,io);
+	devrev=inb(io+1);
+	outb(0x09,io);
+	oldid=inb(io+1);
+	outb(0xaa,io);    /* Magic Seal */
+
+	decode_winbond(io,key,devid,devrev,oldid);
+}
+
+static void winbond_check2(int io,int key)
+{
+        int devid,devrev,oldid;
+
+        outb(key,io);     /* Write Magic Byte to EFER, extended
+                             funtion enable register */
+        outb(0x20,io+2);  /* Write EFIR, extended function index register */
+        devid=inb(io+2);  /* Read EFDR, extended function data register */
+        outb(0x21,io+1);
+        devrev=inb(io+2);
+        outb(0x09,io+1);
+        oldid=inb(io+2);
+        outb(0xaa,io);    /* Magic Seal */
+
+        decode_winbond(io,key,devid,devrev,oldid);
+}
+
+static void smsc_check(int io, int key)
+{
+        int devid,devrev;
+
+        outb(key,io);
+        outb(key,io);     /* Write Magic Sequence to EFER, extended
+                             funtion enable register */
+        outb(0x0d,io);    /* Write EFIR, extended function index register */
+        devid=inb(io+1);  /* Read EFDR, extended function data register */
+        outb(0x0e,io);
+        devrev=inb(io+1);
+        outb(0xaa,io);    /* Magic Seal */
+
+        decode_smsc(io,key,devid,devrev);
+}
+
+
+static void detect_and_report_winbond (void)
+{ 
+	printk("Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n");
+
+	winbond_check(0x3f0,0x87);
+	winbond_check(0x370,0x87);
+	winbond_check(0x2e ,0x87);
+	winbond_check(0x4e ,0x87);
+	winbond_check(0x3f0,0x86);
+	winbond_check2(0x250,0x88); 
+	winbond_check2(0x250,0x89);
+}
+
+static void detect_and_report_smsc (void)
+{
+	printk("SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n");
+	smsc_check(0x3f0,0x55);
+	smsc_check(0x370,0x55);
+	smsc_check(0x3f0,0x44);
+	smsc_check(0x370,0x44);
+}
+
+static int get_superio_dma (struct parport *p)
+{
+	int i=0;
+	while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
+		i++;
+	if (i!=NR_SUPERIOS)
+		return superios[i].dma;
+	return PARPORT_DMA_NONE;
+}
+
+static int get_superio_irq (struct parport *p)
+{
+	int i=0;
+        while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
+                i++;
+        if (i!=NR_SUPERIOS)
+                return superios[i].irq;
+        return PARPORT_IRQ_NONE;
+}
+	
+
 /* --- Mode detection ------------------------------------- */
 
 /*
@@ -1158,9 +1479,12 @@
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
 	int i;
-	int config;
+	int config, configb;
 	int pword;
 	struct parport_pc_private *priv = pb->private_data;
+	int intrline[]={0,7,9,10,11,14,15,5}; /* Translate ECP
+                                                 intrLine to ISA irq
+                                                 value */
 
 	/* If there is no ECR, we have no hope of supporting ECP. */
 	if (!priv->ecr)
@@ -1253,11 +1577,23 @@
 	printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
 		config & 0x80 ? "Level" : "Pulses");
 
-	config = inb (CONFIGB (pb));
-	if (!(config & 0x40)) {
+	configb = inb (CONFIGB (pb));
+	if (!(configb & 0x40)) {
 		printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
 		pb->irq = PARPORT_IRQ_NONE;
 	}
+	printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n",
+		pb->base, config, configb);
+        printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base);
+	if ((configb >>3) & 0x07)
+		printk("%d",intrline[(configb >>3) & 0x07]);
+	else
+		printk("<none or set by other means>");
+	printk ( " dma=");
+	if( (configb & 0x03 ) == 0x00)
+		printk("<none or set by other means>\n");
+	else
+		printk("%d\n",configb & 0x07);
 
 	/* Go back to mode 000 */
 	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
@@ -1476,8 +1812,6 @@
 
 	if (priv->ecr) {
 		pb->irq = programmable_irq_support(pb);
-		if (pb->irq != PARPORT_IRQ_NONE)
-			goto out;
 	}
 
 	if (pb->modes & PARPORT_MODE_ECP)
@@ -1497,7 +1831,9 @@
 	if (pb->irq == PARPORT_IRQ_NONE)
 		pb->irq = irq_probe_SPP(pb);
 
-out:
+	if (pb->irq == PARPORT_IRQ_NONE)
+		pb->irq = get_superio_irq(pb);
+
 	return pb->irq;
 }
 
@@ -1525,7 +1861,12 @@
 {
 	const struct parport_pc_private *priv = p->private_data;
 	if (priv->ecr)
-		p->dma = programmable_dma_support(p);
+		p->dma = programmable_dma_support(p); /* ask ECP chipset first */
+	if (p->dma == PARPORT_DMA_NONE)
+		/* ask known Super-IO chips proper, although these
+		   claim ECP compatible, some don't report their DMA
+		   conforming to ECP standards */
+		p->dma = get_superio_dma(p);
 
 	return p->dma;
 }
@@ -1533,9 +1874,9 @@
 /* --- Initialisation code -------------------------------- */
 
 struct parport *__devinit parport_pc_probe_port (unsigned long int base,
-						    unsigned long int base_hi,
-						    int irq, int dma,
-						    struct pci_dev *dev)
+						 unsigned long int base_hi,
+						 int irq, int dma,
+						 struct pci_dev *dev)
 {
 	struct parport_pc_private *priv;
 	struct parport_operations *ops;
@@ -1625,7 +1966,8 @@
 			parport_dma_probe(p);
 		}
 	}
-	if (p->dma == PARPORT_DMA_AUTO)		
+	if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq
+                                           is mandatory (see above) */
 		p->dma = PARPORT_DMA_NONE;
 
 #ifdef CONFIG_PARPORT_PC_FIFO
@@ -2040,6 +2382,7 @@
 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, };
+static int superio = 0;
 
 MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
 MODULE_DESCRIPTION("PC-style parallel port driver");
@@ -2051,12 +2394,18 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
+MODULE_PARM_DESC(superio, "Enable Super-IO chipset probe");
+MODULE_PARM(superio, "i");
 
 int init_module(void)
 {	
 	/* Work out how many ports we have, then get parport_share to parse
 	   the irq values. */
 	unsigned int i;
+	if (superio) {
+		detect_and_report_winbond ();
+		detect_and_report_smsc ();
+	}
 	for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
 	if (i) {
 		if (parport_parse_irqs(i, irq, irqval)) return 1;
diff -u --recursive --new-file v2.3.49/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.3.49/linux/drivers/pcmcia/yenta.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/pcmcia/yenta.c	Sat Mar  4 10:10:14 2000
@@ -602,7 +602,19 @@
 static int yenta_suspend(pci_socket_t *socket)
 {
 	yenta_set_socket(socket, &dead_socket);
+
+	/*
+	 * This does not work currently. The controller
+	 * loses too much informationduring D3 to come up
+	 * cleanly. We should probably fix yenta_init()
+	 * to update all the critical registers, notably
+	 * the IO and MEM bridging region data.. That is
+	 * something that pci_set_power_state() should
+	 * probably know about bridges anyway.
+	 *
 	pci_set_power_state(socket->dev, 3);
+	 */
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.49/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.3.49/linux/drivers/pnp/isapnp.c	Thu Feb 10 17:11:12 2000
+++ linux/drivers/pnp/isapnp.c	Sat Mar  4 20:04:55 2000
@@ -2040,7 +2040,7 @@
 		if (isapnp_reserve_irq[i] < 0) {
 			isapnp_reserve_irq[i] = irq;
 #ifdef ISAPNP_DEBUG
-			printk("IRQ %i is reserved now.\n", irq);
+			printk("isapnp: IRQ %i is reserved now.\n", irq);
 #endif
 			return 0;
 		}
@@ -2056,7 +2056,7 @@
 
 	pci_for_each_dev(dev) {
 #ifdef ISAPNP_DEBUG
-		printk("PCI: reserved IRQ: %i\n", dev->irq);
+		printk("isapnp: PCI: reserved IRQ: %i\n", dev->irq);
 #endif
 		if (dev->irq > 0)
 			isapnp_do_reserve_irq(dev->irq);
diff -u --recursive --new-file v2.3.49/linux/drivers/pnp/quirks.c linux/drivers/pnp/quirks.c
--- v2.3.49/linux/drivers/pnp/quirks.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/pnp/quirks.c	Sat Mar  4 20:04:55 2000
@@ -45,7 +45,7 @@
 		port3->min += 0x800;
 		port3->max += 0x800;
 	}
-	printk(KERN_INFO "ISAPnP: AWE32 quirk - adding two ports\n");
+	printk(KERN_INFO "isapnp: AWE32 quirk - adding two ports\n");
 }
 
 
@@ -71,7 +71,7 @@
 	while (isapnp_fixups[i].vendor != 0) {
 		if ((isapnp_fixups[i].vendor == dev->vendor) &&
 		    (isapnp_fixups[i].device == dev->device)) {
-			printk(KERN_DEBUG "PnP: Calling quirk for %02x:%02x\n",
+			printk(KERN_DEBUG "isapnp: Calling quirk for %02x:%02x\n",
 			       dev->bus->number, dev->devfn);
 			isapnp_fixups[i].quirk_function(dev);
 		}
diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.3.49/linux/drivers/scsi/pci2000.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/scsi/pci2000.c	Tue Mar  7 11:04:12 2000
@@ -49,16 +49,11 @@
 #include "scsi.h"
 #include "hosts.h"
 #include <linux/stat.h>
+#include <linux/spinlock.h>
 
 #include "pci2000.h"
 #include "psi_roy.h"
 
-#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
-#include <asm/spinlock.h>
-#endif
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
-#include <linux/bios32.h>
-#endif
 
 //#define DEBUG 1
 
diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.3.49/linux/drivers/scsi/pci2220i.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/scsi/pci2220i.c	Tue Mar  7 11:04:12 2000
@@ -47,6 +47,7 @@
 #include <linux/kdev_t.h>
 #include <linux/blk.h>
 #include <linux/timer.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -55,12 +56,6 @@
 #include "pci2220i.h"
 #include "psi_dale.h"
 
-#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
-#include <asm/spinlock.h>
-#endif
-#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
-#include <linux/bios32.h>
-#endif
 
 #define	PCI2220I_VERSION		"2.00"
 #define	READ_CMD				IDE_CMD_READ_MULTIPLE
diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.3.49/linux/drivers/scsi/sg.c	Wed Feb 16 17:03:52 2000
+++ linux/drivers/scsi/sg.c	Tue Mar  7 10:57:47 2000
@@ -7,7 +7,7 @@
  * Original driver (sg.c):
  *        Copyright (C) 1992 Lawrence Foard
  * Version 2 and 3 extensions to driver:
- *        Copyright (C) 1998, 1999 Douglas Gilbert
+ *        Copyright (C) 1998 - 2000 Douglas Gilbert
  *
  *  Modified  19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Devfs support
  *
@@ -17,8 +17,8 @@
  * any later version.
  *
  */
- static char * sg_version_str = "Version: 3.1.10 (20000123)";
- static int sg_version_num = 30110; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 3.1.12 (20000222)";
+ static int sg_version_num = 30112; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -100,6 +100,8 @@
 #define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */
 #define SG_USER_MEM 4   /* memory belongs to user space */
 
+#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
+
 
 static int sg_init(void);
 static int sg_attach(Scsi_Device *);
@@ -109,8 +111,7 @@
 
 static Scsi_Cmnd * dummy_cmdp = 0;    /* only used for sizeof */
 
-
-static spinlock_t sg_request_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED;
 
 struct Scsi_Device_Template sg_template =
 {
@@ -124,7 +125,6 @@
       detach:sg_detach
 };
 
-/* Need to add 'rwlock_t sg_rw_lock = RW_LOCK_UNLOCKED;' for list protection */
 
 typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
 {
@@ -137,7 +137,7 @@
     char mapped;                /* indicates kiobp has locked pages */
     char buffer_mem_src;        /* heap whereabouts of 'buffer' */
     unsigned char cmd_opcode;   /* first byte of command */
-} Sg_scatter_hold;    /* 20 bytes long on i386 */
+} Sg_scatter_hold;    /* 24 bytes long on i386 */
 
 struct sg_device;               /* forward declarations */
 struct sg_fd;
@@ -174,7 +174,7 @@
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
     char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
-} Sg_fd; /* 1212 bytes long on i386 */
+} Sg_fd; /* 2760 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
 {
@@ -186,7 +186,8 @@
     kdev_t i_rdev;      /* holds device major+minor number */
     char exclude;       /* opened for exclusive access */
     char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
-} Sg_device; /* 24 bytes long on i386 */
+    char detached;      /* 0->attached, 1->detached pending removal */
+} Sg_device; /* 40 bytes long on i386 */
 
 
 static int sg_fasync(int fd, struct file * filp, int mode);
@@ -232,8 +233,10 @@
 static int sg_last_dev(void);
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
+static Sg_device * sg_get_dev(int dev);
+
+static Sg_device ** sg_dev_arr = NULL;
 
-static Sg_device * sg_dev_arr = NULL;
 static const int size_sg_header = sizeof(struct sg_header);
 static const int size_sg_io_hdr = sizeof(sg_io_hdr_t);
 static const int size_sg_iovec = sizeof(sg_iovec_t);
@@ -248,10 +251,8 @@
     Sg_fd * sfp;
     int res;
 
-    if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max))
-        return -ENXIO;
-    sdp = &sg_dev_arr[dev];
-    if ((! sdp->device) || (! sdp->device->host))
+    sdp = sg_get_dev(dev);
+    if ((! sdp) || (! sdp->device) || (! sdp->device->host))
         return -ENXIO;
     if (sdp->i_rdev != inode->i_rdev)
         printk("sg_open: inode maj=%d, min=%d   sdp maj=%d, min=%d\n",
@@ -664,6 +665,15 @@
     SCpnt->bufflen = srp->data.bufflen;
     SCpnt->underflow = 0;
     SCpnt->buffer = srp->data.buffer;
+    switch (hp->dxfer_direction) {
+    case SG_DXFER_TO_FROM_DEV:
+    case SG_DXFER_FROM_DEV:
+	SCpnt->sc_data_direction = SCSI_DATA_READ; break;
+    case SG_DXFER_TO_DEV:
+	SCpnt->sc_data_direction = SCSI_DATA_WRITE; break;
+    default:
+	SCpnt->sc_data_direction = SCSI_DATA_NONE; break;
+    }
     srp->data.k_use_sg = 0;
     srp->data.sglist_len = 0;
     srp->data.bufflen = 0;
@@ -946,8 +956,7 @@
     Sg_fd * sfp;
     Sg_request * srp = NULL;
 
-    if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)
-	|| (NULL == (sdp = &sg_dev_arr[dev]))) {
+    if (NULL == (sdp = sg_get_dev(dev))) {
 	SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev));
         scsi_release_command(SCpnt);
         SCpnt = NULL;
@@ -1060,11 +1069,11 @@
         case TYPE_WORM:
         case TYPE_TAPE: break;
         default:
-        printk("Detected scsi generic sg%c at scsi%d,"
-                " channel %d, id %d, lun %d\n",
-               'a'+sg_template.dev_noticed,
+        printk("Detected scsi generic sg%d at scsi%d,"
+                " channel %d, id %d, lun %d, type %d\n",
+               sg_template.dev_noticed,
 	       scsidp->host->host_no, scsidp->channel,
-               scsidp->id, scsidp->lun);
+               scsidp->id, scsidp->lun, scsidp->type);
     }
     sg_template.dev_noticed++;
     return 1;
@@ -1074,36 +1083,37 @@
 static int sg_init()
 {
     static int sg_registered = 0;
-    int size;
+    unsigned long flags = 0;
 
-    if (sg_template.dev_noticed == 0) return 0;
+    if ((sg_template.dev_noticed == 0) || sg_dev_arr)
+    	return 0;
 
+    write_lock_irqsave(&sg_dev_arr_lock, flags);
     if(!sg_registered) {
-        if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
+	if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
         {
             printk("Unable to get major %d for generic SCSI device\n",
                    SCSI_GENERIC_MAJOR);
+	    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
             return 1;
         }
         sg_registered++;
     }
 
-    /* If we have already been through here, return */
-    if(sg_dev_arr) return 0;
-
     SCSI_LOG_TIMEOUT(3, printk("sg_init\n"));
-    size = sizeof(Sg_device) *
-	   (sg_template.dev_noticed + SG_EXTRA_DEVS);
-    sg_dev_arr = (Sg_device *)kmalloc(size, GFP_ATOMIC);
-    memset(sg_dev_arr, 0, size);
+    sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP;
+    sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 
+    					sizeof(Sg_device *), GFP_ATOMIC);
     if (NULL == sg_dev_arr) {
         printk("sg_init: no space for sg_dev_arr\n");
+	write_unlock_irqrestore(&sg_dev_arr_lock, flags);
         return 1;
     }
+    memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *));
+    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
 #ifdef CONFIG_PROC_FS
     sg_proc_init();
 #endif  /* CONFIG_PROC_FS */
-    sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
     return 0;
 }
 
@@ -1130,21 +1140,41 @@
 
 static int sg_attach(Scsi_Device * scsidp)
 {
-    Sg_device * sdp = sg_dev_arr;
+    Sg_device * sdp;
+    unsigned long flags = 0;
     int k;
 
-    if ((sg_template.nr_dev >= sg_template.dev_max) || (! sdp))
-    {
-        scsidp->attached--;
-	printk("sg_attach: rejected since exceeds dev_max=%d\n",
-	       sg_template.dev_max);
-        return 1;
+    write_lock_irqsave(&sg_dev_arr_lock, flags);
+    if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */
+    	Sg_device ** tmp_da;
+	int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP;
+
+	tmp_da = (Sg_device **)kmalloc(tmp_dev_max * 
+    					sizeof(Sg_device *), GFP_ATOMIC);
+	if (NULL == tmp_da) {
+	    scsidp->attached--;
+	    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
+	    printk("sg_attach: device array cannot be resized\n");
+	    return 1;
+	}
+	memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
+	memcpy(tmp_da, sg_dev_arr, sg_template.dev_max * sizeof(Sg_device *));
+	kfree((char *)sg_dev_arr);
+	sg_dev_arr = tmp_da;
+	sg_template.dev_max = tmp_dev_max;
     }
 
-    for(k = 0; k < sg_template.dev_max; k++, sdp++)
-        if(! sdp->device) break;
-
-    if(k >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
+    for(k = 0; k < sg_template.dev_max; k++)
+        if(! sg_dev_arr[k]) break;
+    if(k >= sg_template.dev_max) panic ("sg_dev_arr corrupt");
+
+    sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC);
+    if (NULL == sdp) {
+	scsidp->attached--;
+	write_unlock_irqrestore(&sg_dev_arr_lock, flags);
+	printk("sg_attach: Sg_device cannot be allocated\n");
+	return 1;
+    }
 
     SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
     sdp->device = scsidp;
@@ -1152,13 +1182,16 @@
     sdp->headfp= NULL;
     sdp->exclude = 0;
     sdp->sgdebug = 0;
+    sdp->detached = 0;
     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
     sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
     sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE,
-			      SCSI_GENERIC_MAJOR, k,
-			      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
-			      &sg_fops, NULL);
+                             SCSI_GENERIC_MAJOR, k,
+                             S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+                             &sg_fops, NULL);
     sg_template.nr_dev++;
+    sg_dev_arr[k] = sdp;
+    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
     return 0;
 }
 
@@ -1171,19 +1204,21 @@
 
 static void sg_detach(Scsi_Device * scsidp)
 {
-    Sg_device * sdp = sg_dev_arr;
+    Sg_device * sdp;
     unsigned long flags = 0;
     Sg_fd * sfp;
     Sg_request * srp;
     int k;
 
-    if (NULL == sdp) return; /* all is not well ... */
-    for (k = 0; k < sg_template.dev_max; k++, sdp++) {
-        if(sdp->device != scsidp)
+    if (NULL == sg_dev_arr)
+    	return;
+    write_lock_irqsave(&sg_dev_arr_lock, flags);
+/* Need to stop sg_cmd_done_bh() playing with this list during this loop */
+    for (k = 0; k < sg_template.dev_max; k++) {
+    	sdp = sg_dev_arr[k];
+        if ((NULL == sdp) || (sdp->device != scsidp))
             continue;   /* dirty but lowers nesting */
         if (sdp->headfp) {
-/* Need to stop sg_cmd_done_bh() playing with this list during this loop */
-            spin_lock_irqsave(&sg_request_lock, flags);
             sfp = sdp->headfp;
             while (sfp) {
                 srp = sfp->headrp;
@@ -1194,23 +1229,28 @@
                 }
                 sfp = sfp->nextfp;
             }
-            spin_unlock_irqrestore(&sg_request_lock, flags);
+	    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
     SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k));
             scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */
+	    devfs_unregister (sdp->de);
+	    sdp->de = NULL;
+	    sdp->detached = 1;
+	    write_lock_irqsave(&sg_dev_arr_lock, flags);
         }
         else {
             SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
-	    sdp->device = NULL;
+	    devfs_unregister (sdp->de);
+	    kfree((char *)sdp);
+	    sg_dev_arr[k] = NULL;
         }
-	devfs_unregister (sdp->de);
-	sdp->de = NULL;
         scsidp->attached--;
         sg_template.nr_dev--;
 /* avoid associated device /dev/sg? being incremented
  * each time module is inserted/removed , <dan@lectra.fr> */
         sg_template.dev_noticed--;
-        return;
+        break;
     }
+    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
     return;
 }
 
@@ -1252,7 +1292,7 @@
 
 /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */
 static void sg_shorten_timeout(Scsi_Cmnd * scpnt)
-{
+{	/* assumed to be called with sg_dev_arr_lock held */
 #if 0 /* scsi_syms.c is very miserly about exported functions */
     scsi_delete_timer(scpnt);
     if (! scpnt)
@@ -1265,9 +1305,10 @@
                        scsi_old_times_out);
 #else
     unsigned long flags = 0;
-    spin_lock_irqsave(&sg_request_lock, flags);
+
+    write_unlock_irqrestore(&sg_dev_arr_lock, flags);
     scsi_sleep(HZ); /* just sleep 1 second and hope ... */
-    spin_unlock_irqrestore(&sg_request_lock, flags);
+    write_lock_irqsave(&sg_dev_arr_lock, flags);
 #endif
 }
 
@@ -1986,7 +2027,7 @@
 }
 
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
-{
+{	/* if this is to be locked remember that it is called from _bh */
     Sg_request * srp;
     Sg_request * tsrp;
     int dirty = 0;
@@ -1994,7 +2035,6 @@
 
     srp = sfp->headrp;
     if (srp) {
-/* Need to stop sg_cmd_done_bh() playing with this list during this loop */
         while (srp) {
             tsrp = srp->nextrp;
 	    if (srp->done)
@@ -2027,6 +2067,18 @@
         sfp->parentdp = NULL;
 	SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%p\n", sfp));
 	sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src);
+	if (sdp->detached && (NULL == sdp->headfp)) {
+	    int k, maxd;
+
+	    maxd = sg_template.dev_max;
+	    for (k = 0; k < maxd; ++k) {
+	    	if (sdp == sg_dev_arr[k])
+		    break;
+	    }
+	    if (k < maxd)
+		sg_dev_arr[k] = NULL;
+	    kfree((char *)sdp);
+	}
         res = 1;
     }
     else {
@@ -2264,15 +2316,31 @@
 
 
 static int sg_last_dev()
-{
+{	/* assumed to be called with sg_dev_arr_lock held */
     int k;
+
     for (k = sg_template.dev_max - 1; k >= 0; --k) {
-	if (sg_dev_arr[k].device)
+	if (sg_dev_arr[k] && sg_dev_arr[k]->device)
 	    return k + 1;
     }
     return 0;   /* origin 1 */
 }
 
+static Sg_device * sg_get_dev(int dev)
+{
+    Sg_device * sdp;
+
+    if ((NULL == sg_dev_arr) || (dev < 0))
+    	return NULL;
+    read_lock(&sg_dev_arr_lock);
+    if (dev < sg_template.dev_max)
+    	sdp = sg_dev_arr[dev];
+    else
+    	sdp = NULL;
+    read_unlock(&sg_dev_arr_lock);
+    return sdp;
+}
+
 #ifdef CONFIG_PROC_FS
 
 static struct proc_dir_entry * sg_proc_sgp = NULL;
@@ -2427,36 +2495,35 @@
 static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
 			      off_t offset, int size)
 {
-    const Sg_device * sdp = sg_dev_arr;
+    Sg_device * sdp;
     const sg_io_hdr_t * hp;
     int j, max_dev;
 
     if (NULL == sg_dev_arr) {
-	PRINT_PROC("sg_dev_arr NULL, death is imminent\n");
+	PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
 	return 1;
     }
+    read_lock(&sg_dev_arr_lock);
     max_dev = sg_last_dev();
     PRINT_PROC("dev_max=%d max_active_device=%d (origin 1)\n",
 	       sg_template.dev_max, max_dev);
     PRINT_PROC(" scsi_dma_free_sectors=%u sg_pool_secs_aval=%d "
 	       "def_reserved_size=%d\n",
 	       scsi_dma_free_sectors, sg_pool_secs_avail, sg_big_buff);
-    max_dev = sg_last_dev();
-    for (j = 0; j < max_dev; ++j, ++sdp) {
-	if (sdp) {
+    for (j = 0; j < max_dev; ++j) {
+	if ((sdp = sg_dev_arr[j])) {
 	    Sg_fd * fp;
 	    Sg_request * srp;
 	    struct scsi_device * scsidp;
-	    int dev, k, blen, usg, crep;
+	    int dev, k, blen, usg;
 
 	    if (! (scsidp = sdp->device)) {
 		PRINT_PROC("device %d detached ??\n", j);
 		continue;
 	    }
 	    dev = MINOR(sdp->i_rdev);
-	    crep = 'a' + dev;
 
-	    PRINT_PROC(" >>> device=%d(sg%c) ", dev, crep > 126 ? '?' : crep);
+	    PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev);
 	    PRINT_PROC("scsi%d chan=%d id=%d lun=%d   em=%d sg_tablesize=%d"
 		       " excl=%d\n", scsidp->host->host_no, scsidp->channel,
 		       scsidp->id, scsidp->lun, scsidp->host->hostt->emulated,
@@ -2496,6 +2563,7 @@
 	    }
 	}
     }
+    read_unlock(&sg_dev_arr_lock);
     return 1;
 }
 
@@ -2506,23 +2574,23 @@
 static int sg_proc_dev_info(char * buffer, int * len, off_t * begin,
 			    off_t offset, int size)
 {
-    const Sg_device * sdp = sg_dev_arr;
+    Sg_device * sdp;
     int j, max_dev;
     struct scsi_device * scsidp;
 
+    read_lock(&sg_dev_arr_lock);
     max_dev = sg_last_dev();
-    for (j = 0; j < max_dev; ++j, ++sdp) {
-	if (sdp) {
-	    if (! (scsidp = sdp->device)) {
-		PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
-		continue;
-	    }
+    for (j = 0; j < max_dev; ++j) {
+	sdp = sg_dev_arr[j];
+	if (sdp && (scsidp = sdp->device))
 	    PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
 	       scsidp->host->host_no, scsidp->channel, scsidp->id,
 	       scsidp->lun, (int)scsidp->type, (int)scsidp->disconnect,
 	       (int)scsidp->queue_depth, (int)scsidp->tagged_queue);
-	}
+	else
+	    PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
     }
+    read_unlock(&sg_dev_arr_lock);
     return 1;
 }
 
@@ -2544,20 +2612,21 @@
 static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin,
 				off_t offset, int size)
 {
-    const Sg_device * sdp = sg_dev_arr;
+    Sg_device * sdp;
     int j, max_dev;
     struct scsi_device * scsidp;
 
+    read_lock(&sg_dev_arr_lock);
     max_dev = sg_last_dev();
-    for (j = 0; j < max_dev; ++j, ++sdp) {
-	if (sdp) {
-	    if ((scsidp = sdp->device))
-		PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
-			   scsidp->vendor, scsidp->model, scsidp->rev);
-	    else
-		PRINT_PROC("<no active device>\n");
-	}
+    for (j = 0; j < max_dev; ++j) {
+	sdp = sg_dev_arr[j];
+	if (sdp && (scsidp = sdp->device))
+	    PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
+		       scsidp->vendor, scsidp->model, scsidp->rev);
+	else
+	    PRINT_PROC("<no active device>\n");
     }
+    read_unlock(&sg_dev_arr_lock);
     return 1;
 }
 
@@ -2569,12 +2638,16 @@
 			     off_t offset, int size)
 {
     struct Scsi_Host * shp;
+    int k;
 
-    for (shp = scsi_hostlist; shp; shp = shp->next)
+    for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
+    	for ( ; k < shp->host_no; ++k)
+	    PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n");
 	PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n",
 		   shp->unique_id, shp->host_busy, shp->cmd_per_lun,
 		   shp->sg_tablesize, (int)shp->unchecked_isa_dma,
 		   (int)shp->hostt->emulated);
+    }
     return 1;
 }
 
@@ -2597,10 +2670,14 @@
 				 off_t offset, int size)
 {
     struct Scsi_Host * shp;
+    int k;
 
-    for (shp = scsi_hostlist; shp; shp = shp->next)
+    for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
+    	for ( ; k < shp->host_no; ++k)
+	    PRINT_PROC("<no active host>\n");
 	PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) :
 		    (shp->hostt->name ? shp->hostt->name : "<no name>"));
+    }
     return 1;
 }
 
diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.3.49/linux/drivers/scsi/sr.c	Sun Feb 20 21:12:39 2000
+++ linux/drivers/scsi/sr.c	Fri Mar  3 12:59:50 2000
@@ -666,11 +666,7 @@
 	/* scsi_wait_cmd sets the command length */
 	SRpnt->sr_cmd_len = 0;
 
-	/*
-	 * FIXME(eric) - need to set the data direction here.
-	 */
-	SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
-
+	SRpnt->sr_data_direction = cgc->data_direction;
 	scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
 		      SR_TIMEOUT, MAX_RETRIES);
 
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.3.49/linux/drivers/sound/Config.in	Tue Feb  1 01:35:44 2000
+++ linux/drivers/sound/Config.in	Tue Mar  7 13:40:24 2000
@@ -81,79 +81,21 @@
 dep_tristate '  OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
 
 if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
-   if [ "$CONFIG_SOUND_OSS" = "y" ]; then
-      bool '    Persistent DMA buffers' CONFIG_SOUND_DMAP
-   fi
-
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       dep_tristate '    AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND
-      if [ "$CONFIG_SOUND_AD1816" = "y" ]; then
-	 hex 'AD1816 audio I/O base 530, 604, E80 or F40' CONFIG_AD1816_BASE 530
-	 int 'AD1816 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_AD1816_IRQ 7
-	 int 'AD1816 audio DMA 0, 1 or 3' CONFIG_AD1816_DMA 0
-	 int 'AD1816 second (duplex) DMA 0, 1 or 3' CONFIG_AD1816_DMA2 3
-	 int 'AD1816 clock chip frequency' CONFIG_AD1816_CLOCK 33000
-      fi
    fi
 
    dep_tristate '    Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_SGALAXY" = "y" ]; then
-      hex 'SGALAXY audio I/O base 530, 604, E80 or F40' CONFIG_SGALAXY_BASE 530
-      int 'SGALAXY audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_SGALAXY_IRQ 11
-      int 'SGALAXY audio DMA 0, 1 or 3' CONFIG_SGALAXY_DMA 0
-      int 'SGALAXY second (duplex) DMA 0, 1 or 3' CONFIG_SGALAXY_DMA2 3
-      hex 'SGALAXY SB I/O base 220 or 240' CONFIG_SGALAXY_SGBASE 220
-   fi
-
    dep_tristate '    Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_CS4232" = "y" ]; then
-      hex 'CS4232 audio I/O base (normally 530, 604, E80 or F40)' CONFIG_CS4232_BASE 530
-      int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11
-      int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0
-      int 'CS4232 second (duplex) DMA 0, 1 or 3' CONFIG_CS4232_DMA2 3
-      hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_CS4232_MPU_BASE 330
-      int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9
-   fi
-
    dep_tristate '    Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_SSCAPE" = "y" ]; then
-      hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' CONFIG_SSCAPE_BASE 330
-      int 'SoundScape MIDI IRQ ' CONFIG_SSCAPE_IRQ 9
-      int 'SoundScape initialization DMA 0, 1 or 3' CONFIG_SSCAPE_DMA 3
-      hex 'SoundScape audio I/O base 534, 608, E84 or F44' CONFIG_SSCAPE_MSS_BASE 534
-      int 'SoundScape audio IRQ 7, 9, 10 or 11' CONFIG_SSCAPE_MSS_IRQ 11
-   fi
-
    dep_tristate '    Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then
-      bool '      16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 
-      bool '      GUS MAX support' CONFIG_GUSMAX
-   fi
-   if [ "$CONFIG_SOUND_GUS" = "y" ]; then
-      hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220
-      int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15
-      int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6
-      int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1
-      if [ "$CONFIG_GUS16" = "y" ]; then
-	 hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530
-	 int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7
-	 int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3
-      fi
+   if [ "$CONFIG_SOUND_GUS" != "n" ]; then
+      bool '      16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_SOUND_GUS16 
+      bool '      GUS MAX support' CONFIG_SOUND_GUSMAX
    fi
-
    dep_tristate '    Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS
-
    dep_tristate '    MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_TRIX" = "y" ]; then
-      hex 'TRIX audio I/O base 530, 604, E80 or F40' CONFIG_TRIX_BASE 530
-      int 'TRIX audio IRQ 7, 9, 10 or 11' CONFIG_TRIX_IRQ 11
-      int 'TRIX audio DMA 0, 1 or 3' CONFIG_TRIX_DMA 0
-      int 'TRIX second (duplex) DMA 0, 1 or 3' CONFIG_TRIX_DMA2 3
-      hex 'TRIX MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_TRIX_MPU_BASE 330
-      int 'TRIX MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_TRIX_MPU_IRQ 9
-      hex 'TRIX SB I/O base 220, 210, 230, 240, 250, 260 or 270' CONFIG_TRIX_SB_BASE 220
-      int 'TRIX SB IRQ 3, 4, 5 or 7' CONFIG_TRIX_SB_IRQ 7
-      int 'TRIX SB DMA 1 or 3' CONFIG_TRIX_SB_DMA 1
       bool '      Have TRXPRO.HEX firmware file' CONFIG_TRIX_HAVE_BOOT
       if [ "$CONFIG_TRIX_HAVE_BOOT" = "y" ]; then
   	string '  Full pathname of TRXPRO.HEX firmware file' CONFIG_TRIX_BOOT_FILE /etc/sound/trxpro.hex
@@ -161,58 +103,23 @@
    fi
   
    dep_tristate '    Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_MSS" = "y" ]; then
-      bool '      Enable support for the SoundPro mixer' CONFIG_SOUND_SPRO
-      hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530
-      int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11
-      int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3
-      int 'MSS/WSS second DMA (if possible) 0, 1 or 3' CONFIG_MSS_DMA2 -1
-   fi
-
    dep_tristate '    MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_MPU401" = "y" ]; then
-      hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330
-      int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9
-   fi
-
    dep_tristate '    NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS
-
    dep_tristate '    OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then
      bool '      Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD
    fi
-   if [ "$CONFIG_SOUND_MAD16" = "y" ]; then
-      hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530
-      int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11
-      int 'MAD16 audio DMA 0, 1 or 3' CONFIG_MAD16_DMA 3
-      int 'MAD16 second (duplex) DMA 0, 1 or 3' CONFIG_MAD16_DMA2 0
-      hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' CONFIG_MAD16_MPU_BASE 330
-      int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9
-   fi
-
    dep_tristate '    ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_PAS" = "y" ]; then
-      int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10
-      int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3
-      bool '      Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK
-   fi
+   dep_bool '      Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK $CONFIG_SOUND_PAS
 
    dep_tristate '    PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_SOUND_PSS $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_PSS" = "y" ]; then
-      hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220
-      hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530
-      int 'PSS audio IRQ 7, 9, 10 or 11' CONFIG_PSS_MSS_IRQ 11
-      int 'PSS audio DMA 0, 1 or 3' CONFIG_PSS_MSS_DMA 3
-      hex 'PSS MIDI I/O base ' CONFIG_PSS_MPU_BASE 330
-      int 'PSS MIDI IRQ 3, 4, 5, 7, 9, 10, 11, 12' CONFIG_PSS_MPU_IRQ 9
-      bool '      Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
-      if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
-         string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
-      fi
-   fi
    if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then
       bool '      Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER
    fi
+   bool '      Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
+   if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
+      string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
+   fi
 
    dep_tristate '    SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_SOFTOSS" = "y" ]; then
@@ -221,27 +128,9 @@
    fi
   
    dep_tristate '    100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_SB" = "y" ]; then
-      hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
-      int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7
-      int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1
-      int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' CONFIG_SB_DMA2 5
-      hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' CONFIG_SB_MPU_BASE 330
-      comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
-      comment 'Enter -1 to the following question if you have something else such as SB16/32.'
-      int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1
-   fi
-  
    dep_tristate '    Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
-   if [ "$CONFIG_SOUND_WAVEFRONT" = "y" ]; then
-      hex 'I/O base for WaveFront 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_WAVEFRONT_BASE 330
-      int 'WaveFront IRQ 5, 9, 12 or 15' CONFIG_WAVEFRONT_IRQ 9
-   fi
-
    dep_tristate '    Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
-      hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330
-      int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9
       bool '      Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT
       if [ "$CONFIG_MAUI_HAVE_BOOT" = "y" ]; then
   	 string '  Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE /etc/sound/oswf.mot
@@ -249,47 +138,14 @@
    fi
 
    dep_tristate '    VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_SOUND_OSS
-
    dep_tristate '    Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS
- 
    dep_tristate '    Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_OPL3SA1" = "y" ]; then
-      hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA1_BASE 530
-      int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_OPL3SA1_IRQ 11
-      int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA 0
-      int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA2 3
-      hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA1_MPU_BASE 330
-      int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_OPL3SA1_MPU_IRQ 9
-   fi
-  
    dep_tristate '    Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then
-      int 'Chipset (-1 for autoprobe, 2, or 3)' CONFIG_OPL3SA2_CHIPSET -1
-      hex 'OPL3SA2 audio I/O base (530 - F48 valid)' CONFIG_OPL3SA2_BASE 530
-      int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 9
-      int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0
-      int 'OPL3SA2 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA2 1
-      hex 'OPL3SA2 control I/O base (100 - FFE valid)' CONFIG_OPL3SA2_CTRL_BASE 370
-      hex 'OPL3SA2 MIDI I/O base (300 - 334 valid)' CONFIG_OPL3SA2_MPU_BASE 330
-      int 'OPL3SA2 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_MPU_IRQ 9
-   fi
-  
-  
    dep_tristate '    6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS
-   if [ "$CONFIG_SOUND_UART6850" = "y" ]; then
-      hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0
-      int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1
-   fi
   
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
       dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS
-      if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then
-	 hex '    WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250
-	 int '  WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 12
-	 int '  WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3
-	 int '  WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7
-      fi
    fi
   
   
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.49/linux/drivers/sound/Makefile	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/Makefile	Tue Mar  7 13:40:24 2000
@@ -23,7 +23,7 @@
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
 export-objs	:=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
-		    msnd.o opl3.o sb_card.o sequencer_syms.o \
+		    msnd.o opl3.o sb_common.o sequencer_syms.o \
 		    sound_core.o sound_syms.o uart401.o ad1816.o \
 		    nm256_audio.o ac97.o ac97_codec.o
 
@@ -45,39 +45,36 @@
 obj-$(CONFIG_SOUND_OSS)		+= sound.o
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o ad1848.o 
 
-# In theory, there's probably no reason to include the uart401 code
-# to support a WaveFront card's CS4232 module. However, it makes
-# reconfiguring things require a recompile, so just leave this
-# here and try not to worry about the extra uart401 module.
+# Please leave it as is, cause the link order is significant !
 
-obj-$(CONFIG_SOUND_CS4232)	+= uart401.o
+obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
+obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_OPL3SA1)     += opl3sa.o ad1848.o uart401.o
+obj-$(CONFIG_SOUND_SOFTOSS)     += softoss2.o
+obj-$(CONFIG_SOUND_SSCAPE)      += sscape.o ad1848.o mpu401.o
+obj-$(CONFIG_SOUND_MAD16)       += mad16.o ad1848.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o uart401.o
+obj-$(CONFIG_SOUND_OPL3SA2)     += opl3sa2.o ad1848.o uart401.o mpu401.o
+obj-$(CONFIG_SOUND_MSS)         += ad1848.o
+obj-$(CONFIG_SOUND_PAS)         += pas2.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_SB)          += sb.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_WAVEFRONT)   += wavefront.o
+obj-$(CONFIG_SOUND_MAUI)        += maui.o mpu401.o
+obj-$(CONFIG_SOUND_MPU401)      += mpu401.o
+obj-$(CONFIG_SOUND_UART6850)    += uart6850.o
 obj-$(CONFIG_SOUND_GUS)		+= gus.o ad1848.o
-obj-$(CONFIG_SOUND_MAD16)	+= mad16.o ad1848.o sb.o uart401.o
-obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o sb.o uart401.o ac97.o
-obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
-obj-$(CONFIG_SOUND_MPU401)	+= mpu401.o
+obj-$(CONFIG_SOUND_YM3812)      += adlib_card.o opl3.o
+obj-$(CONFIG_SOUND_VMIDI)       += v_midi.o
+obj-$(CONFIG_SOUND_VIDC)        += vidc_mod.o
+obj-$(CONFIG_SOUND_WAVEARTIST)  += waveartist.o
+obj-$(CONFIG_SOUND_SGALAXY)     += sgalaxy.o ad1848.o
+obj-$(CONFIG_SOUND_AD1816)      += ad1816.o
+
+obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o sb_lib.o uart401.o ac97.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
-obj-$(CONFIG_SOUND_MSS)		+= ad1848.o
-obj-$(CONFIG_SOUND_OPL3SA1)	+= opl3sa.o ad1848.o uart401.o
-obj-$(CONFIG_SOUND_OPL3SA2)	+= opl3sa2.o ad1848.o uart401.o mpu401.o
-obj-$(CONFIG_SOUND_PAS)		+= pas2.o sb.o uart401.o
-obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_SB)		+= sb.o uart401.o
-obj-$(CONFIG_SOUND_SOFTOSS)	+= softoss2.o
-obj-$(CONFIG_SOUND_SGALAXY)	+= sgalaxy.o ad1848.o
-obj-$(CONFIG_SOUND_AD1816)	+= ad1816.o
-obj-$(CONFIG_SOUND_SSCAPE)	+= sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb.o uart401.o
-obj-$(CONFIG_SOUND_UART6850)	+= uart6850.o
-obj-$(CONFIG_SOUND_VMIDI)	+= v_midi.o
-obj-$(CONFIG_SOUND_YM3812)	+= adlib_card.o opl3.o
-obj-$(CONFIG_SOUND_VIDC)	+= vidc_mod.o
 obj-$(CONFIG_SOUND_VWSND)	+= vwsnd.o
-obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
-obj-$(CONFIG_SOUND_WAVEFRONT)   += wavefront.o
-obj-$(CONFIG_SOUND_NM256)	+= nm256.o
-
+obj-$(CONFIG_SOUND_NM256)	+= nm256_audio.o ac97.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 obj-$(CONFIG_SOUND_CMPCI)	+= cmpci.o
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
@@ -89,7 +86,7 @@
 # Declare multi-part drivers.
 
 list-multi	:= sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
-    soundcore.o wavefront.o nm256.o
+    soundcore.o wavefront.o
 
 sound-objs	:= 							\
     dev_table.o soundcard.o sound_syms.o		\
@@ -101,12 +98,11 @@
 
 gus-objs	:= gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
 pas2-objs	:= pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
-sb-objs		:= sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o	\
-			   sb_ess.o
+sb-objs		:= sb_card.o
+sb_lib-objs	:= sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o
 softoss2-objs	:= softoss.o softoss_rs.o
 vidc_mod-objs	:= vidc.o vidc_fill.o
 wavefront-objs  := wavfront.o wf_midi.o yss225.o
-nm256-objs	:= nm256_audio.o ac97.o
 
 
 # Extract lists of the multi-part drivers.
@@ -125,20 +121,6 @@
 int-m		:= $(filter-out $(int-y), $(int-m))
 
 
-
-# Set flags for secondary drivers.
-# I have to do this before I reduce obj-y to components.
-
-EXTRA_CFLAGS	:= $(sort					\
-    $(patsubst ad1848.o,  -DCONFIG_SOUND_AD1848,		\
-    $(patsubst mpu401.o,  -DCONFIG_SOUND_MPU_EMU,		\
-    $(patsubst sb.o,      -DCONFIG_SOUND_SBDSP,			\
-    $(patsubst uart401.o, -DCONFIG_SOUND_UART401,		\
-	$(filter ad1848.o mpu401.o sb.o uart401.o, $(obj-y))	\
-    )))))
-
-
-
 # Take multi-part drivers out of obj-y and put components in.
 
 obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
@@ -155,8 +137,8 @@
 OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
 M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
 MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
-MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+#MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+#MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
 
 ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
     O_OBJS	+= lowlevel/lowlevel.o
@@ -183,6 +165,9 @@
 sb.o: $(sb-objs)
 	$(LD) -r -o $@ $(sb-objs)
 
+sb_lib.o: $(sb_lib-objs)
+	$(LD) -r -o $@ $(sb_lib-objs)
+
 softoss2.o: $(softoss2-objs)
 	$(LD) -r -o $@ $(softoss2-objs)
 
@@ -191,9 +176,6 @@
 
 wavefront.o: $(wavefront-objs)
 	$(LD) -r -o $@ $(wavefront-objs)
-
-nm256.o: $(nm256-objs)
-	$(LD) -r -o $@ $(nm256-objs)
 
 # Firmware files that need translation
 #
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- v2.3.49/linux/drivers/sound/ac97_codec.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/ac97_codec.c	Thu Mar  2 22:44:07 2000
@@ -20,6 +20,8 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * History
+ * v0.3 Feb 22 2000 Ollie Lho
+ *	bug fix for record mask setting
  * v0.2 Feb 10 2000 Ollie Lho
  *	add ac97_read_proc for /proc/driver/vnedor/ac97
  * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
@@ -40,7 +42,9 @@
 static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
 static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
 
-#define arraysize(x)	(sizeof(x)/sizeof((x)[0]))
+static int sigmatel_init(struct ac97_codec * codec);
+
+#define arraysize(x)   (sizeof(x)/sizeof((x)[0]))
 
 static struct {
 	unsigned int id;
@@ -50,14 +54,16 @@
 	{0x414B4D00, "Asahi Kasei AK4540"     , NULL},
 	{0x41445340, "Analog Devices AD1881"  , NULL},
 	{0x43525900, "Cirrus Logic CS4297"    , NULL},
+	{0x43525903, "Cirrus Logic CS4297"  ,	NULL},
 	{0x43525913, "Cirrus Logic CS4297A"   , NULL},
+	{0x43525923, "Cirrus Logic CS4298"    , NULL},
 	{0x43525931, "Cirrus Logic CS4299"    , NULL},
-	{0x4e534331, "National Semiconductor LM4549", NULL},
+	{0x4e534331, "National Semiconductor LM4549" ,	NULL},
 	{0x83847600, "SigmaTel STAC????"      , NULL},
 	{0x83847604, "SigmaTel STAC9701/3/4/5", NULL},
 	{0x83847605, "SigmaTel STAC9704"      , NULL},
 	{0x83847608, "SigmaTel STAC9708"      , NULL},
-	{0x83847609, "SigmaTel STAC9721/23"   , NULL},
+	{0x83847609, "SigmaTel STAC9721/23"   , sigmatel_init},
 	{0x54524108, "TriTech TR28028"        , NULL},
 	{0x574D4C00, "Wolfson WM9704"         , NULL},
 	{0x00000000, NULL, NULL}
@@ -156,11 +162,12 @@
 };
 
 static unsigned int ac97_rm2oss[] = {
-	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC, 
-	[AC97_REC_CD] 	 = SOUND_MIXER_CD, 
-	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, 
-	[AC97_REC_AUX] 	 = SOUND_MIXER_LINE1, 
-	[AC97_REC_LINE]  = SOUND_MIXER_LINE, 
+	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC,
+	[AC97_REC_CD] 	 = SOUND_MIXER_CD,
+	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
+	[AC97_REC_AUX] 	 = SOUND_MIXER_LINE1,
+	[AC97_REC_LINE]  = SOUND_MIXER_LINE,
+	[AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
 	[AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
 };
 
@@ -171,6 +178,7 @@
 	[SOUND_MIXER_VIDEO] 	= AC97_REC_VIDEO,
 	[SOUND_MIXER_LINE1] 	= AC97_REC_AUX,
 	[SOUND_MIXER_LINE] 	= AC97_REC_LINE,
+	[SOUND_MIXER_IGAIN]	= AC97_REC_STEREO,
 	[SOUND_MIXER_PHONEIN] 	= AC97_REC_PHONE
 };
 
@@ -216,8 +224,10 @@
 	}
 
 #ifdef DEBUG
-	printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), "
-	       "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret);
+	printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
+	       "0x%04x -> 0x%04x\n",
+	       oss_channel, codec->id ? "Secondary" : "Primary",
+	       mh->offset, val, ret);
 #endif
 
 	return ret;
@@ -269,6 +279,7 @@
 #ifdef DEBUG
 	printk(" 0x%04x", val);
 #endif
+
 	codec->codec_write(codec, mh->offset, val);
 
 #ifdef DEBUG
@@ -303,8 +314,11 @@
 
 	if (rw) {
 		/* read it from the card */
-		val = codec->codec_read(codec, 0x1a) & 0x7;
-		return ac97_rm2oss[val];
+		val = codec->codec_read(codec, AC97_RECORD_SELECT);
+#ifdef DEBUG
+		printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
+#endif
+		return (1 << ac97_rm2oss[val & 0x07]);
 	}
 
 	/* else, write the first set in the mask as the
@@ -315,10 +329,10 @@
 	val |= val << 8;  /* set both channels */
 
 #ifdef DEBUG
-	printk("ac97_codec: setting ac97 recmask to 0x%x\n", val);
+	printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
 #endif
 
-	codec->codec_write(codec, 0x1a, val);
+	codec->codec_write(codec, AC97_RECORD_SELECT, val);
 
 	return 0;
 };
@@ -384,9 +398,9 @@
 				return -EINVAL;
 
 			/* do we ever want to touch the hardware? */
-			val = codec->read_mixer(codec, i);
-			/* val = codec->mixer_state[i]; */
-			break;
+		        /* val = codec->read_mixer(codec, i); */
+			val = codec->mixer_state[i];
+ 			break;
 		}
 		return put_user(val, (int *)arg);
 	}
@@ -497,9 +511,10 @@
 	codec->codec_write(codec, AC97_RESET, 0L);
 	if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000)
 		return 0;
-	
+
 	codec->name = NULL;
 	codec->codec_init = NULL;
+
 	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
 	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
 	for (i = 0; i < arraysize(ac97_codec_ids); i++) {
@@ -520,6 +535,8 @@
 	codec->record_sources = AC97_RECORD_MASK;
 	if (!(cap & 0x04))
 		codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
+	if (!(cap & 0x10))
+		codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
 
 	/* generic OSS to AC97 wrapper */
 	codec->read_mixer = ac97_read_mixer;
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ad1816.c linux/drivers/sound/ad1816.c
--- v2.3.49/linux/drivers/sound/ad1816.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/ad1816.c	Tue Mar  7 13:40:24 2000
@@ -1,59 +1,43 @@
 /*
-
-AD1816 lowlevel sound driver for Linux 2.2.0 and above
-
-Copyright (C) 1998 by Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
-Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996
-
-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
-
--------------------------------------------------------------------------------
-NOTE!   NOTE!   NOTE!   NOTE!   NOTE!   NOTE!   NOTE!   NOTE!   NOTE!
-
-This software is still under development. New versions of the driver 
-are available from:
-  http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
-or
-  http://www.tu-darmstadt.de/~tek01/projects/linux.html
-
-Please report any bugs to: tek@rbg.informatik.tu-darmstadt.de
-
--------------------------------------------------------------------------------
-
-version: 1.3
-cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $
-status: experimental
-date: 1999/4/18
-
-Changes:
-	Oleg Drokin: Some cleanup of load/unload functions.    1998/11/24
-	
-	Thorsten Knabe: attach and unload rewritten, 
-	some argument checks added                             1998/11/30
-
-	Thorsten Knabe: Buggy isa bridge workaround added      1999/01/16
-	
-	David Moews/Thorsten Knabe: Introduced options 
-	parameter. Added slightly modified patch from 
-	David Moews to disable dsp audio sources by setting 
-	bit 0 of options parameter. This seems to be
-	required by some Aztech/Newcom SC-16 cards.            1999/04/18
-	
-*/
+ *
+ * AD1816 lowlevel sound driver for Linux 2.2.0 and above
+ *
+ * Copyright (C) 1998 by Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
+ *
+ * Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996
+ *
+ * This software is still under development. New versions of the driver 
+ * are available from:
+ * http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
+ * or http://www.tu-darmstadt.de/~tek01/projects/linux.html
+ * 
+ * Please report any bugs to: tek@rbg.informatik.tu-darmstadt.de
+ *
+ *
+ * version: 1.3
+ * cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $
+ * status: experimental
+ * date: 1999/4/18
+ *
+ * Changes:
+ *	Oleg Drokin: Some cleanup of load/unload functions.	1998/11/24
+ *	
+ *	Thorsten Knabe: attach and unload rewritten, 
+ *	some argument checks added				1998/11/30
+ *
+ *	Thorsten Knabe: Buggy isa bridge workaround added	1999/01/16
+ *	
+ *	David Moews/Thorsten Knabe: Introduced options 
+ *	parameter. Added slightly modified patch from 
+ *	David Moews to disable dsp audio sources by setting 
+ *	bit 0 of options parameter. This seems to be
+ *	required by some Aztech/Newcom SC-16 cards.		1999/04/18
+ *
+ *	Christoph Hellwig: Adapted to module_init/module_exit.	2000/03/03
+ */
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/stddef.h>
 #include "soundmodule.h"
 #include "sound_config.h"
@@ -96,14 +80,10 @@
 	int            irq_ok;
 	int            *osp;
   
-}
-
-ad1816_info;
-
-static int  nr_ad1816_devs = 0;
-
-static int  ad1816_clockfreq=33000;
+} ad1816_info;
 
+static int nr_ad1816_devs = 0;
+static int ad1816_clockfreq=33000;
 static int options=0;
 
 /* for backward mapping of irq to sound device */
@@ -617,7 +597,8 @@
 
 /* Interrupt handler */
 
-void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
+
+static void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
 {
 	unsigned char   status;
 	ad1816_info    *devc;
@@ -1089,7 +1070,7 @@
 
 
 /* replace with probe routine */
-int probe_ad1816 ( struct address_info *hw_config )
+static int __init probe_ad1816 ( struct address_info *hw_config )
 {
 	ad1816_info    *devc = &dev_info[nr_ad1816_devs];
 	int io_base=hw_config->io_base;
@@ -1097,7 +1078,6 @@
 	int tmp;
 	
 	printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n");
-	printk("ad1816: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $\n");
 	printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n",
 	       hw_config->io_base,
 	       hw_config->irq,
@@ -1183,7 +1163,7 @@
   
  */
 
-void attach_ad1816 (struct address_info *hw_config)
+static void __init attach_ad1816 (struct address_info *hw_config)
 {
 	int             my_dev;
 	char            dev_name[100];
@@ -1309,7 +1289,7 @@
 	}
 }
 
-void unload_card(ad1816_info *devc)
+static void __exit unload_card(ad1816_info *devc)
 {
 	int  mixer, dev = 0;
 	
@@ -1343,51 +1323,12 @@
 	}
 }
 
-void unload_ad1816 (struct address_info *hw_config)
-{
-	int          i;
-	ad1816_info  *devc = NULL;
-  
-	/* remove any soundcard */
-	if (hw_config==NULL) {
-		for (i = 0;  i < nr_ad1816_devs; i++) {
-			devc = &dev_info[i];
-			unload_card(devc);
-		}     
-		nr_ad1816_devs=0;
-	} else { 
-		/* remove specified soundcard */
-		for (i = 0; i < nr_ad1816_devs; i++) {
-		        int j;
-			
-			if (dev_info[i].base == hw_config->io_base) {
-				devc = &dev_info[i];
-				unload_card(devc);
-				nr_ad1816_devs--;
-				for ( j=i; j < nr_ad1816_devs ; j++) {
-					dev_info[j] = dev_info[j+1];
-				}
-				i--;
-			}
-		}
-	}
-}
-
-
-/* ----------------------------- 2.1.xxx module stuff ----------------- */
-
-EXPORT_SYMBOL(ad1816_interrupt);
-EXPORT_SYMBOL(probe_ad1816);
-EXPORT_SYMBOL(attach_ad1816);
-EXPORT_SYMBOL(unload_ad1816);
+static struct address_info cfg;
 
-
-#ifdef MODULE
-
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma2 = -1;
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata dma2 = -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
@@ -1396,33 +1337,59 @@
 MODULE_PARM(ad1816_clockfreq,"i");
 MODULE_PARM(options,"i");
 
-struct address_info cfg;
+static int __init init_ad1816(void)
+{
+	cfg.io_base     = io;
+	cfg.irq         = irq;
+	cfg.dma         = dma;
+	cfg.dma2        = dma2;
 
+	if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.dma2 == -1) {
+		printk(KERN_INFO "ad1816: dma, dma2, irq and io must be set.\n");
+		return -EINVAL;
+	}
 
-int init_module(void)
-{
-        if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) {
-		printk("ad1816: dma, dma2, irq and io must be set.\n");
-                return -EINVAL;
-        }
-        cfg.io_base = io;
-        cfg.irq = irq;
-        cfg.dma = dma;
-        cfg.dma2 = dma2;
-	
-        if (probe_ad1816(&cfg) == 0) {
-                return -ENODEV;
+	if (probe_ad1816(&cfg) == 0) {
+		return -ENODEV;
 	}
-        attach_ad1816(&cfg);
-        SOUND_LOCK;
-        return 0;
+	
+	attach_ad1816(&cfg);
+	SOUND_LOCK;
 }
 
+static void __exit cleanup_ad1816 (void)
+{
+	int          i;
+	ad1816_info  *devc = NULL;
+  
+	/* remove any soundcard */
+	for (i = 0;  i < nr_ad1816_devs; i++) {
+		devc = &dev_info[i];
+		unload_card(devc);
+	}     
+	nr_ad1816_devs=0;
 
-void cleanup_module(void)
+	SOUND_LOCK_END;
+}
+
+module_init(init_ad1816);
+module_exit(cleanup_ad1816);
+
+#ifndef MODULE
+static int __init setup_ad1816(char *str)
 {
-        unload_ad1816(NULL);
-        SOUND_LOCK_END;
+	/* io, irq, dma, dma2 */
+	int ints[5];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma16	= ints[4];
+
+	return 1;
 }
 
-#endif /* MODULE */
+__setup("ad1816=", setup_ad1816);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.3.49/linux/drivers/sound/ad1848.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/ad1848.c	Tue Mar  7 13:40:24 2000
@@ -22,16 +22,18 @@
  * for more info.
  *
  *
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
- *		     general sleep/wakeup clean up.
- * Alan Cox	   : reformatted. Fixed SMP bugs. Moved to kernel alloc/free
- *		     of irqs. Use dev_id.
+ * Thomas Sailer	: ioctl code reworked (vmalloc/vfree removed)
+ *			  general sleep/wakeup clean up.
+ * Alan Cox		: reformatted. Fixed SMP bugs. Moved to kernel alloc/free
+ *		          of irqs. Use dev_id.
+ * Christoph Hellwig	: adapted to module_init/module_exit
  *
  * Status:
  *		Tested. Believed fully functional.
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/stddef.h>
 
@@ -40,6 +42,8 @@
 #define DEB(x)
 #define DEB1(x)
 #include "sound_config.h"
+
+#include "ad1848.h"
 #include "ad1848_mixer.h"
 
 typedef struct
@@ -99,23 +103,19 @@
 static int nr_ad1848_devs = 0;
 int deskpro_xl = 0;
 int deskpro_m = 0;
-#ifdef CONFIG_SOUND_SPRO
-int soundpro = 1;
-#else
 int soundpro = 0;
-#endif
 
 static volatile signed char irq2dev[17] = {
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1, -1
 };
 
-#ifdef MODULE
-
+#ifndef EXCLUDE_TIMERS
 static int timer_installed = -1;
-
 #endif
 
+static int loaded = 0;
+
 static int ad_format_mask[10 /*devc->model */ ] =
 {
 	0,
@@ -2502,6 +2502,11 @@
 	int dma = hw_config->dma;
 	int dma2 = hw_config->dma2;
 
+	if(hw_config->io_base != -1 || hw_config->irq == -1 || hw_config->dma == -1) {
+		printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n");
+		return;
+	}
+
 	if (hw_config->card_subtype == 1)	/* Has no IRQ/DMA registers */
 	{
 		hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
@@ -2568,6 +2573,9 @@
 					  dma2, 0,
 					  hw_config->osp);
 	request_region(hw_config->io_base, 4, "WSS config");
+
+	SOUND_LOCK;
+	loaded = 1;
 }
 
 void unload_ms_sound(struct address_info *hw_config)
@@ -2702,8 +2710,6 @@
 EXPORT_SYMBOL(attach_ms_sound);
 EXPORT_SYMBOL(unload_ms_sound);
 
-#ifdef MODULE
-
 MODULE_PARM(io, "i");			/* I/O for a raw AD1848 card */
 MODULE_PARM(irq, "i");			/* IRQ to use */
 MODULE_PARM(dma, "i");			/* First DMA channel */
@@ -2713,45 +2719,57 @@
 MODULE_PARM(deskpro_m, "i");		/* Special magic for Deskpro M box */
 MODULE_PARM(soundpro, "i");		/* More special magic for SoundPro chips */
 
-int io = -1;
-int irq = -1;
-int dma = -1;
-int dma2 = -1;
-int type = 0;
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata dma2 = -1;
+static int __initdata type = 0;
 
-static int loaded = 0;
-
-struct address_info hw_config;
+static struct address_info cfg;
 
-int init_module(void)
+static int __init init_ad1848(void)
 {
 	printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-	if(io != -1)
-	{
-		if(irq == -1 || dma == -1)
-		{
-			printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n");
-			return -EINVAL;
-		}
-		hw_config.irq = irq;
-		hw_config.io_base = io;
-		hw_config.dma = dma;
-		hw_config.dma2 = dma2;
-		hw_config.card_subtype = type;
-		if(!probe_ms_sound(&hw_config))
-			return -ENODEV;
-		attach_ms_sound(&hw_config);
-		loaded=1;
-	}
-	SOUND_LOCK;
-	return 0;
+
+	cfg.irq = irq;
+	cfg.io_base = io;
+	cfg.dma = dma;
+	cfg.dma2 = dma2;
+	cfg.card_subtype = type;
+
+	if(probe_ms_sound(&cfg)) {
+		attach_ms_sound(&cfg);
+		return 0;
+	} else
+		return -ENODEV;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_ad1848(void)
 {
 	SOUND_LOCK_END;
 	if(loaded)
-		unload_ms_sound(&hw_config);
+		unload_ms_sound(&cfg);
 }
 
-#endif /* MODULE */
+module_init(init_ad1848);
+module_exit(cleanup_ad1848);
+
+#ifndef MODULE
+static int __init setup_ad1848(char *str)
+{
+        /* io, irq, dma, dma2, type */
+	int ints[6];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma2	= ints[4];
+	type	= ints[5];
+
+	return 1;
+}
+
+__setup("ad1848=", setup_ad1848);	
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ad1848.h linux/drivers/sound/ad1848.h
--- v2.3.49/linux/drivers/sound/ad1848.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/ad1848.h	Tue Mar  7 13:40:24 2000
@@ -0,0 +1,28 @@
+/*
+ * ad1848.c
+ *
+ * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
+ */
+
+#define AD_F_CS4231     0x0001  /* Returned if a CS4232 (or compatible) detected */
+#define AD_F_CS4248     0x0001  /* Returned if a CS4248 (or compatible) detected */
+
+#define         AD1848_SET_XTAL         1
+#define         AD1848_MIXER_REROUTE    2
+
+#define AD1848_REROUTE(oldctl, newctl) \
+                ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl))
+		
+
+int ad1848_init(char *name, int io_base, int irq, int dma_playback,
+	int dma_capture, int share_dma, int *osp);
+void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma);
+
+int ad1848_detect (int io_base, int *flags, int *osp);
+int ad1848_control(int cmd, int arg);
+
+void adintr(int irq, void *dev_id, struct pt_regs * dummy);
+void attach_ms_sound(struct address_info * hw_config);
+
+int probe_ms_sound(struct address_info *hw_config);
+void unload_ms_sound(struct address_info *hw_info);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c
--- v2.3.49/linux/drivers/sound/adlib_card.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/adlib_card.c	Tue Mar  7 13:40:24 2000
@@ -11,47 +11,42 @@
  */
 
 #include <linux/module.h>
+#include <linux/init.h>
+
 #include "sound_config.h"
 #include "soundmodule.h"
 
-void attach_adlib_card(struct address_info *hw_config)
+#include "opl3.h"
+
+static void __init attach_adlib_card(struct address_info *hw_config)
 {
 	hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp);
 	request_region(hw_config->io_base, 4, "OPL3/OPL2");
 }
 
-int probe_adlib(struct address_info *hw_config)
+static int __init probe_adlib(struct address_info *hw_config)
 {
-	if (check_region(hw_config->io_base, 4)) 
-	{
+	if (check_region(hw_config->io_base, 4)) {
 		DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base));
 		return 0;
 	}
 	return opl3_detect(hw_config->io_base, hw_config->osp);
 }
 
-void unload_adlib(struct address_info *hw_config)
-{
-	release_region(hw_config->io_base, 4);
-	sound_unload_synthdev(hw_config->slots[0]);
-}
+static struct address_info cfg;
 
-#ifdef MODULE
+static int __initdata io = -1;
 
-int io = -1;
 MODULE_PARM(io, "i");
 
-EXPORT_NO_SYMBOLS;
-
-struct address_info cfg;
-
-int init_module(void)
+static int __init init_adlib(void)
 {
-	if (io == -1) {
+	cfg.io_base = io;
+
+	if (cfg.io_base == -1) {
 		printk(KERN_ERR "adlib: must specify I/O address.\n");
 		return -EINVAL;
 	}
-	cfg.io_base = io;
 	if (probe_adlib(&cfg) == 0)
 		return -ENODEV;
 	attach_adlib_card(&cfg);
@@ -59,10 +54,27 @@
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_adlib(void)
 {
-	unload_adlib(&cfg);
+	release_region(cfg.io_base, 4);
+	sound_unload_synthdev(cfg.slots[0]);
+	
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_adlib);
+module_exit(cleanup_adlib);
+
+#ifndef MODULE
+static int __init setup_adlib(char *str)
+{
+        /* io */
+	int ints[2];
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io = ints[1];
+
+	return 1;
+}
+__setup("adlib=", setup_adlib);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v2.3.49/linux/drivers/sound/cs4232.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/cs4232.c	Tue Mar  7 13:40:24 2000
@@ -1,5 +1,7 @@
 /*
- * sound/cs4232.c
+ * Copyright (C) by Hannu Savolainen 1993-1997
+ *
+ *	cs4232.c
  *
  * The low level driver for Crystal CS4232 based cards. The CS4232 is
  * a PnP compatible chip which contains a CS4231A codec, SB emulation,
@@ -35,22 +37,21 @@
  *	Alan Cox		Modularisation, Basic cleanups.
  *      Paul Barton-Davis	Separated MPU configuration, added
  *                                       Tropez+ (WaveFront) support
- */
-
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
+ *	Christoph Hellwig	Adapted to module_init/module_exit,
+ * 					simple cleanups
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 
+#include "cs4232.h"
+#include "ad1848.h"
+#include "mpu401.h"
+
 #define KEY_PORT	0x279	/* Same as LPT1 status port */
 #define CSN_NUM		0x99	/* Just a random number */
 
@@ -78,11 +79,6 @@
 	return 1;
 }
 
-void attach_cs4232_mpu(struct address_info *hw_config)
-{
-	/* Nothing needs doing */
-}
-
 static unsigned char crystal_key[] =	/* A 32 byte magic key sequence */
 {
 	0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
@@ -215,8 +211,15 @@
 
 void attach_cs4232(struct address_info *hw_config)
 {
-	int base = hw_config->io_base, irq = hw_config->irq;
-	int dma1 = hw_config->dma, dma2 = hw_config->dma2;
+	int base = hw_config->io_base,
+		irq = hw_config->irq,
+		dma1 = hw_config->dma,
+		dma2 = hw_config->dma2;
+
+	if (base == -1 || irq == -1 || dma1 == -1) {
+		printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
+		return;
+	}
 
 	if (dma2 == -1)
 		dma2 = dma1;
@@ -263,6 +266,7 @@
 		}
 		hw_config->slots[1] = hw_config2.slots[1];
 	}
+	SOUND_LOCK;
 }
 
 void unload_cs4232(struct address_info *hw_config)
@@ -302,19 +306,18 @@
 	}
 }
 
-void unload_cs4232_mpu(struct address_info *hw_config)
-{
-	/* Not required. Handled by cs4232_unload */
-}
+static struct address_info cfg;
+static struct address_info cfg_mpu;
 
-#ifdef MODULE
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma2	= -1;
+static int __initdata mpuio	= -1;
+static int __initdata mpuirq	= -1;
+static int __initdata synthio	= -1;
+static int __initdata synthirq	= -1;
 
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma2 = -1;
-int             mpuio = -1;
-int             mpuirq = -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
@@ -322,34 +325,20 @@
 MODULE_PARM(dma2,"i");
 MODULE_PARM(mpuio,"i");
 MODULE_PARM(mpuirq,"i");
-
-int             synthio = -1;
-int             synthirq = -1;
 MODULE_PARM(synthio,"i");
 MODULE_PARM(synthirq,"i");
 
-EXPORT_NO_SYMBOLS;
-
-struct address_info cfg;
-struct address_info mpu_cfg;
-
 /*
  *	Install a CS4232 based card. Need to have ad1848 and mpu401
  *	loaded ready.
  */
 
-int init_module(void)
+static int __init init_cs4232(void)
 {
-	if (io == -1 || irq == -1 || dma == -1 || dma2 == -1)
-	{
-		printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n");
-		return -EINVAL;
-	}
 #ifdef CONFIG_SOUND_WAVEFRONT_MODULE
 	if(synthio == -1)
 		printk(KERN_WARNING "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
-	else
-	{
+	else {
 		synth_base = synthio;
 		synth_irq =  synthirq;	
 	}
@@ -363,32 +352,48 @@
 	cfg.dma = dma;
 	cfg.dma2 = dma2;
 
-	mpu_cfg.io_base = -1;
-	mpu_cfg.irq = -1;
+	cfg_mpu.io_base = -1;
+	cfg_mpu.irq = -1;
 
 	if (mpuio != -1 && mpuirq != -1) {
-		mpu_cfg.io_base = mpuio;
-		mpu_cfg.irq = mpuirq;
-		probe_cs4232_mpu(&mpu_cfg); /* Bug always returns 0 not OK -- AC */
+		cfg_mpu.io_base = mpuio;
+		cfg_mpu.irq = mpuirq;
+		probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */
 	}
 
 	if (probe_cs4232(&cfg) == 0)
 		return -ENODEV;
-
 	attach_cs4232(&cfg);
-
-	if (mpuio != -1 && mpuirq != -1) {
-		attach_cs4232_mpu(&mpu_cfg);
-	}
-
-	SOUND_LOCK;
+	
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_cs4232(void)
 {
         unload_cs4232(&cfg); /* unloads MPU as well, if needed */
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_cs4232);
+module_exit(cleanup_cs4232);
+
+#ifndef MODULE
+static int __init setup_cs4232(char *str)
+{
+	/* io, irq, dma, dma2 mpuio, mpuirq*/
+	int ints[7];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma2	= ints[4];
+	mpuio	= ints[5];
+	mpuirq	= ints[6];
+
+	return 1;
+}
+
+__setup("cs4232=", setup_cs4232);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/cs4232.h linux/drivers/sound/cs4232.h
--- v2.3.49/linux/drivers/sound/cs4232.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/cs4232.h	Tue Mar  7 13:40:24 2000
@@ -0,0 +1,11 @@
+/*
+ *	cs4232.h
+ *
+ * Copyright: Christoph Hellwig <chhellwig@gmx.net>
+ *
+ */
+
+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);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v2.3.49/linux/drivers/sound/dev_table.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/dev_table.c	Tue Mar  7 13:40:24 2000
@@ -2,9 +2,8 @@
  * sound/dev_table.c
  *
  * Device call tables.
- */
-
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -15,7 +14,6 @@
 #include <linux/config.h>
 #include <linux/init.h>
 
-
 #define _DEV_TABLE_C_
 #include "sound_config.h"
 
@@ -23,387 +21,6 @@
 int sound_started = 0;
 int sndtable_get_cardcount(void);
 
-int snd_find_driver(int type)
-{
-	int i, n = num_sound_drivers;
-
-	for (i = 0; i < n; i++)
-		if (sound_drivers[i].card_type == type)
-			return i;
-
-	return -1;
-}
-
-static void start_services(void)
-{
-#ifdef FIXME
-	int soundcards_installed;
-
-	if (!(soundcards_installed = sndtable_get_cardcount()))
-		return;		/* No cards detected */
-#endif
-
-	if (num_audiodevs)	/* Audio devices present */
-	{
-		int             dev;
-		for (dev = 0; dev < num_audiodevs; dev++)
-		{
-		}
-		audio_init_devices();
-	  }
-
-	return;
-}
-
-static void
-start_cards(void)
-{
-	int i, n = num_sound_cards;
-	int drv;
-
-	sound_started = 1;
-	if (trace_init)
-		printk(KERN_DEBUG "Sound initialization started\n");
-
-#ifdef CONFIG_LOWLEVEL_SOUND
-	{
-		extern void sound_preinit_lowlevel_drivers(void);
-		sound_preinit_lowlevel_drivers();
-	}
-#endif
-
-/*
- * Check the number of cards actually defined in the table
- */
-
-	for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
-		num_sound_cards = i + 1;
-
-	for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
-	{
-		if (snd_installed_cards[i].enabled)
-		{
-			snd_installed_cards[i].for_driver_use = NULL;
-
-			if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1)
-			{
-				snd_installed_cards[i].enabled = 0;	/*
-									 * Mark as not detected
-									 */
-				continue;
-			}
-			snd_installed_cards[i].config.card_subtype =
-					sound_drivers[drv].card_subtype;
-
-			if (sound_drivers[drv].probe(&snd_installed_cards[i].config))
-				sound_drivers[drv].attach(&snd_installed_cards[i].config);
-			else
-				snd_installed_cards[i].enabled = 0;	/*
-									 * Mark as not detected
-									 */
-		}
-	}
-#ifdef CONFIG_LOWLEVEL_SOUND
-	{
-		extern void     sound_init_lowlevel_drivers(void);
-		sound_init_lowlevel_drivers();
-	}
-#endif
-	if (trace_init)
-		printk(KERN_DEBUG "Sound initialization complete\n");
-}
-
-void sndtable_init(void)
-{
-	start_cards();
-}
-
-
-void sound_unload_drivers(void)
-{
-	int i, n = num_sound_cards;
-	int drv;
-
-	if (!sound_started)
-		return;
-
-	if (trace_init)
-		printk(KERN_DEBUG "Sound unload started\n");
-
-
-	for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
-	{
-		if (snd_installed_cards[i].enabled)
-		{
-			if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)
-			{
-				if (sound_drivers[drv].unload)
-				{
-					sound_drivers[drv].unload(&snd_installed_cards[i].config);
-					snd_installed_cards[i].enabled = 0;
-				}
-			}
-		}
-	}
-
-        for (i=0;i<num_audiodevs;i++)
-		DMAbuf_deinit(i);
-
-	if (trace_init)
-		printk(KERN_DEBUG "Sound unload complete\n");
-}
-
-void sound_unload_driver(int type)
-{
-	int i, drv = -1, n = num_sound_cards;
-
-
-	DEB(printk("unload driver %d: ", type));
-
-	for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
-	{
-		if (snd_installed_cards[i].card_type == type)
-		{
-			if (snd_installed_cards[i].enabled)
-			{
-				if ((drv = snd_find_driver(type)) != -1)
-				{
-					DEB(printk(" card %d", i));
-					if (sound_drivers[drv].unload)
-					{
-						sound_drivers[drv].unload(&snd_installed_cards[i].config);
-						snd_installed_cards[i].enabled = 0;
-					}
-				}
-			}
-		}
-	}
-	DEB(printk("\n"));
-}
-
-
-int sndtable_probe(int unit, struct address_info *hw_config)
-{
-	int             sel = -1;
-
-	DEB(printk(KERN_DEBUG "sndtable_probe(%d)\n", unit));
-
-	if (!unit)
-		return 1;
-
-
-	if (sel == -1 && num_sound_cards < max_sound_cards)
-	{
-		int i;
-		i = sel = (num_sound_cards++);
-		snd_installed_cards[sel].card_type = unit;
-		snd_installed_cards[sel].enabled = 1;
-	}
-	if (sel != -1)
-	{
-		int             drv;
-
-		snd_installed_cards[sel].for_driver_use = NULL;
-		snd_installed_cards[sel].config.io_base = hw_config->io_base;
-		snd_installed_cards[sel].config.irq = hw_config->irq;
-		snd_installed_cards[sel].config.dma = hw_config->dma;
-		snd_installed_cards[sel].config.dma2 = hw_config->dma2;
-		snd_installed_cards[sel].config.name = hw_config->name;
-		snd_installed_cards[sel].config.always_detect = hw_config->always_detect;
-		snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1;
-		snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2;
-		snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype;
-
-		if ((drv = snd_find_driver(snd_installed_cards[sel].card_type)) == -1)
-		{
-			snd_installed_cards[sel].enabled = 0;
-			DEB(printk(KERN_DEBUG "Failed to find driver\n"));
-			return 0;
-		}
-		DEB(printk(KERN_DEBUG "Driver name '%s'\n", sound_drivers[drv].name));
-
-		hw_config->card_subtype = snd_installed_cards[sel].config.card_subtype = sound_drivers[drv].card_subtype;
-
-		if (sound_drivers[drv].probe(hw_config))
-		{
-			DEB(printk(KERN_DEBUG "Hardware probed OK\n"));
-			return 1;
-		}
-		DEB(printk("Failed to find hardware\n"));
-		snd_installed_cards[sel].enabled = 0;		/*
-								 * Mark as not detected
-								 */
-		return 0;
-	}
-	return 0;
-}
-
-
-int sndtable_init_card(int unit, struct address_info *hw_config)
-{
-	int i, n = num_sound_cards;
-
-	DEB(printk("sndtable_init_card(%d) entered\n", unit));
-
-	if (!unit)
-	{
-		sndtable_init();
-		return 1;
-	}
-	for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
-	{
-		if (snd_installed_cards[i].card_type == unit)
-		{
-			int drv;
-
-			snd_installed_cards[i].config.io_base = hw_config->io_base;
-			snd_installed_cards[i].config.irq = hw_config->irq;
-			snd_installed_cards[i].config.dma = hw_config->dma;
-			snd_installed_cards[i].config.dma2 = hw_config->dma2;
-			snd_installed_cards[i].config.name = hw_config->name;
-			snd_installed_cards[i].config.always_detect = hw_config->always_detect;
-			snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1;
-			snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2;
-			snd_installed_cards[i].config.card_subtype = hw_config->card_subtype;
-
-			if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1)
-				snd_installed_cards[i].enabled = 0;	/*
-									 * Mark as not detected
-									 */
-			else
-			{
-				DEB(printk(KERN_DEBUG "Located card - calling attach routine\n"));
-				sound_drivers[drv].attach(hw_config);
-
-				DEB(printk("attach routine finished\n"));
-			}
-			start_services();
-			return 1;
-		}
-	}
-	DEB(printk("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards));
-	return 0;
-}
-
-int sndtable_get_cardcount(void)
-{
-	return num_audiodevs + num_mixers + num_synths + num_midis;
-}
-
-int sndtable_identify_card(char *name)
-{
-	int i, n = num_sound_drivers;
-
-	if (name == NULL)
-		return 0;
-
-	for (i = 0; i < n; i++)
-	{
-		if (sound_drivers[i].driver_id != NULL)
-		{
-			char *id = sound_drivers[i].driver_id;
-			int j;
-
-			for (j = 0; j < 80 && name[j] == id[j]; j++)
-				if (id[j] == 0 && name[j] == 0)	/* Match */
-					return sound_drivers[i].card_type;
-		}
-	}
-	return 0;
-}
-
-static int __init sound_setup(char *str)
-{
-	int i, n = num_sound_cards;
-	int ints[32];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	/*
-	 *	First disable all drivers
-	 */
-
-	for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
-		snd_installed_cards[i].enabled = 0;
-
-	if (ints[0] == 0 || ints[1] == 0)
-		return 1;
-	/*
-	 *	Then enable them one by time
-	 */
-
-	for (i = 1; i <= ints[0]; i++)
-	{
-		int card_type, ioaddr, irq, dma, dma2, ptr, j;
-		unsigned int val;
-
-		val = (unsigned int) ints[i];
-		card_type = (val & 0x0ff00000) >> 20;
-
-		if (card_type > 127)
-		{
-			/*
-			 * Add any future extensions here
-			 */
-			return 1;
-		}
-		ioaddr = (val & 0x000fff00) >> 8;
-		irq = (val & 0x000000f0) >> 4;
-		dma = (val & 0x0000000f);
-		dma2 = (val & 0xf0000000) >> 28;
-
-		ptr = -1;
-		for (j = 0; j < n && ptr == -1; j++)
-		{
-			if (snd_installed_cards[j].card_type == card_type &&
-				!snd_installed_cards[j].enabled)/*
-								 * Not already found
-								 */
-				ptr = j;
-		}
-
-		if (ptr == -1)
-			printk(KERN_ERR "Sound: Invalid setup parameter 0x%08x\n", val);
-		else
-		{
-			snd_installed_cards[ptr].enabled = 1;
-			snd_installed_cards[ptr].config.io_base = ioaddr;
-			snd_installed_cards[ptr].config.irq = irq;
-			snd_installed_cards[ptr].config.dma = dma;
-			snd_installed_cards[ptr].config.dma2 = dma2;
-			snd_installed_cards[ptr].config.name = NULL;
-			snd_installed_cards[ptr].config.always_detect = 0;
-			snd_installed_cards[ptr].config.driver_use_1 = 0;
-			snd_installed_cards[ptr].config.driver_use_2 = 0;
-			snd_installed_cards[ptr].config.card_subtype = 0;
-		}
-	}
-	
-	return 1;
-}
-
-__setup("sound=", sound_setup);
-
-
-struct address_info * sound_getconf(int card_type)
-{
-	int j, ptr;
-	int n = num_sound_cards;
-
-	ptr = -1;
-	for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++)
-	{
-		if (snd_installed_cards[j].card_type == card_type)
-			ptr = j;
-	}
-	if (ptr == -1)
-		return (struct address_info *) NULL;
-
-	return &snd_installed_cards[ptr].config;
-}
-
-
-
 int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
 			int driver_size, int flags, unsigned int format_mask,
 			void *devc, int dma1, int dma2)
@@ -619,4 +236,3 @@
 	if (dev != -1)
 		sound_timer_devs[dev] = NULL;
 }
-
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.3.49/linux/drivers/sound/dev_table.h	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/dev_table.h	Tue Mar  7 13:40:24 2000
@@ -370,318 +370,6 @@
 int num_sound_timers = 0;
 #endif
 
-/*
- * List of low level drivers compiled into the kernel.
- */
-
-struct driver_info sound_drivers[] = 
-{
-#ifdef CONFIG_SOUND_PSS
-	{"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss},
-	{"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu},
-	{"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss},
-#endif
-
-#ifdef CONFIG_SOUND_GUS
-#ifdef CONFIG_GUS16
-	{"GUS16", 0, SNDCARD_GUS16,	"Ultrasound 16-bit opt.",	attach_gus_db16, probe_gus_db16, unload_gus_db16},
-#endif
-	{"GUS", 0, SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus, unload_gus},
-	{"GUSPNP", 1, SNDCARD_GUSPNP,	"GUS PnP",	attach_gus_card, probe_gus, unload_gus},
-#endif
-
-#ifdef CONFIG_SOUND_MSS
-	{"MSS", 0, SNDCARD_MSS,	"MS Sound System",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
-	/* Compaq Deskpro XL */
-	{"DESKPROXL", 2, SNDCARD_DESKPROXL,	"Compaq Deskpro XL",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
-#endif
-
-#ifdef CONFIG_SOUND_MAD16
-	{"MAD16", 0, SNDCARD_MAD16,	"MAD16/Mozart (MSS)",		attach_mad16, probe_mad16, unload_mad16},
-	{"MAD16MPU", 0, SNDCARD_MAD16_MPU,	"MAD16/Mozart (MPU)",		attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu},
-#endif
-
-#ifdef CONFIG_SOUND_CS4232
-	{"CS4232", 0, SNDCARD_CS4232,	"CS4232",		attach_cs4232, probe_cs4232, unload_cs4232},
-#endif
-#ifdef CONFIG_CS4232_MPU_BASE
-	{"CS4232MPU", 0, SNDCARD_CS4232_MPU,	"CS4232 MIDI",		attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu},
-#endif
-
-#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
-
-#ifdef CONFIG_SGALAXY
-	{"SGALAXY", 0, SNDCARD_SGALAXY,	"Sound Galaxy WSS",		attach_sgalaxy, probe_sgalaxy, unload_sgalaxy},
-#endif
-
-#ifdef CONFIG_SOUND_AD1816
-        {"AD1816", 0, SNDCARD_AD1816,   "AD1816",               attach_ad1816, 
-probe_ad1816, unload_ad1816},
-#endif
-
-#ifdef CONFIG_SOUND_YM3812
-	{"OPL3", 0, SNDCARD_ADLIB,	"OPL-2/OPL-3 FM",		attach_adlib_card, probe_adlib, unload_adlib},
-#endif
-
-#ifdef CONFIG_SOUND_PAS
-	{"PAS16", 0, SNDCARD_PAS,	"ProAudioSpectrum",	attach_pas_card, probe_pas, unload_pas},
-#endif
-
-#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU))
-	{"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401",	attach_mpu401, probe_mpu401, unload_mpu401},
-#endif
-
-#if defined(CONFIG_SOUND_UART401)
-	{"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", 
-		attach_uart401, probe_uart401, unload_uart401},
-#endif
-
-#if defined(CONFIG_SOUND_WAVEFRONT)
-	{"WAVEFRONT", 0, SNDCARD_WAVEFRONT,"TB WaveFront", attach_wavefront, probe_wavefront, unload_wavefront},
-#endif
-
-#if defined(CONFIG_SOUND_MAUI)
-	{"MAUI", 0, SNDCARD_MAUI,"TB Maui",	attach_maui, probe_maui, unload_maui},
-#endif
-
-#if defined(CONFIG_SOUND_UART6850)
-	{"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi",	attach_uart6850, probe_uart6850, unload_uart6850},
-#endif
-
-
-
-
-#ifdef CONFIG_SOUND_SBDSP
-	{"SBLAST", 0, SNDCARD_SB,	"Sound Blaster",		attach_sb_card, probe_sb, unload_sb},
-	{"SBPNP", 6, SNDCARD_SBPNP,	"Sound Blaster PnP",		attach_sb_card, probe_sb, unload_sb},
-
-	{"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401",	attach_sbmpu, probe_sbmpu, unload_sbmpu},
-#endif
-
-#ifdef CONFIG_SOUND_SSCAPE
-	{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape",	attach_sscape, probe_sscape, unload_sscape},
-	{"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS,	"MS Sound System (SoundScape)",	attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound},
-#endif
-
-#ifdef CONFIG_SOUND_OPL3SA1
-	{"OPL3SA", 0, SNDCARD_OPL3SA1, "Yamaha OPL3-SA",	attach_opl3sa_wss, probe_opl3sa_wss, unload_opl3sa_wss}, 
-/*	{"OPL3SASB", 0, SNDCARD_OPL3SA1_SB, "OPL3-SA (SB mode)",	attach_opl3sa_sb, probe_opl3sa_sb, unload_opl3sa_sb}, */
-	{"OPL3SAMPU", 0, SNDCARD_OPL3SA1_MPU, "OPL3-SA MIDI",	attach_opl3sa_mpu, probe_opl3sa_mpu, unload_opl3sa_mpu},
-#endif
-
-#ifdef CONFIG_SOUND_TRIX
-	{"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro",	attach_trix_wss, probe_trix_wss, unload_trix_wss},
-	{"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)",	attach_trix_sb, probe_trix_sb, unload_trix_sb},
-	{"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI",	attach_trix_mpu, probe_trix_mpu, unload_trix_mpu},
-#endif
-
-#ifdef CONFIG_SOUND_SOFTOSS
-	{"SOFTSYN", 0, SNDCARD_SOFTOSS,	"SoftOSS Virtual Wave Table", 
-		attach_softsyn_card, probe_softsyn, unload_softsyn},
-#endif
-
-#ifdef CONFIG_SOUND_VMIDI
-	{"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device",      attach_v_midi, probe_v_midi, unload_v_midi},
-#endif
-#ifdef CONFIG_SOUND_VIDC
-	{"VIDC", 0, SNDCARD_VIDC, "ARM VIDC 16-bit D/A", attach_vidc, probe_vidc, unload_vidc },
-#endif
-#ifdef CONFIG_SOUND_WAVEARTIST
-	{"WaveArtist", 0, SNDCARD_WAVEARTIST, "NetWinder WaveArtist", attach_waveartist, probe_waveartist, unload_waveartist },
-#endif
-	{NULL, 0, 0,		"*?*",			NULL, NULL, NULL}
-};
-
-int num_sound_drivers = sizeof(sound_drivers) / sizeof (struct driver_info);
-
-
-/*
- *	List of devices actually configured in the system.
- *
- *	Note! The detection order is significant. Don't change it.
- */
-
-struct card_info snd_installed_cards[] = 
-{
-#ifdef CONFIG_SOUND_PSS
-	{SNDCARD_PSS, {CONFIG_PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
-#ifdef CONFIG_PSS_MPU_BASE
-	{SNDCARD_PSS_MPU, {CONFIG_PSS_MPU_BASE, CONFIG_PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#ifdef CONFIG_PSS_MSS_BASE
-	{SNDCARD_PSS_MSS, {CONFIG_PSS_MSS_BASE, CONFIG_PSS_MSS_IRQ, CONFIG_PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_TRIX
-#ifndef CONFIG_TRIX_DMA2
-#define CONFIG_TRIX_DMA2 CONFIG_TRIX_DMA
-#endif
-	{SNDCARD_TRXPRO, {CONFIG_TRIX_BASE, CONFIG_TRIX_IRQ, CONFIG_TRIX_DMA, CONFIG_TRIX_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef CONFIG_TRIX_SB_BASE
-	{SNDCARD_TRXPRO_SB, {CONFIG_TRIX_SB_BASE, CONFIG_TRIX_SB_IRQ, CONFIG_TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE},
-#endif
-#ifdef CONFIG_TRIX_MPU_BASE
-	{SNDCARD_TRXPRO_MPU, {CONFIG_TRIX_MPU_BASE, CONFIG_TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_OPL3SA1
-	{SNDCARD_OPL3SA1, {CONFIG_OPL3SA1_BASE, CONFIG_OPL3SA1_IRQ, CONFIG_OPL3SA1_DMA, CONFIG_OPL3SA1_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef CONFIG_OPL3SA1_MPU_BASE
-	{SNDCARD_OPL3SA1_MPU, {CONFIG_OPL3SA1_MPU_BASE, CONFIG_OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_SOFTOSS
-	{SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_SSCAPE
-	{SNDCARD_SSCAPE, {CONFIG_SSCAPE_BASE, CONFIG_SSCAPE_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
-	{SNDCARD_SSCAPE_MSS, {CONFIG_SSCAPE_MSS_BASE, CONFIG_SSCAPE_MSS_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_MAD16
-#ifndef CONFIG_MAD16_DMA2
-#define CONFIG_MAD16_DMA2 CONFIG_MAD16_DMA
-#endif
-	{SNDCARD_MAD16, {CONFIG_MAD16_BASE, CONFIG_MAD16_IRQ, CONFIG_MAD16_DMA, CONFIG_MAD16_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef CONFIG_MAD16_MPU_BASE
-	{SNDCARD_MAD16_MPU, {CONFIG_MAD16_MPU_BASE, CONFIG_MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_CS4232
-#ifndef CONFIG_CS4232_DMA2
-#define CONFIG_CS4232_DMA2 CONFIG_CS4232_DMA
-#endif
-#ifdef CONFIG_CS4232_MPU_BASE
-	{SNDCARD_CS4232_MPU, {CONFIG_CS4232_MPU_BASE, CONFIG_CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-	{SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_OPL3SA2
-#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, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SGALAXY
-#ifndef CONFIG_SGALAXY_DMA2
-#define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA
-#endif
-	{SNDCARD_SGALAXY, {CONFIG_SGALAXY_BASE, CONFIG_SGALAXY_IRQ, CONFIG_SGALAXY_DMA, CONFIG_SGALAXY_DMA2, 0, NULL, CONFIG_SGALAXY_SGBASE}, SND_DEFAULT_ENABLE},
-#endif
-
-
-#ifdef CONFIG_SOUND_MSS
-#ifndef CONFIG_MSS_DMA2
-#define CONFIG_MSS_DMA2 -1
-#endif
-
-#ifdef DESKPROXL
-	{SNDCARD_DESKPROXL, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE},
-#else
-	{SNDCARD_MSS, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef MSS2_BASE
-	{SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_PAS
-	{SNDCARD_PAS, {CONFIG_PAS_BASE, CONFIG_PAS_IRQ, CONFIG_PAS_DMA, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_SB
-#ifndef CONFIG_SB_DMA
-#define CONFIG_SB_DMA		1
-#endif
-#ifndef CONFIG_SB_DMA2
-#define CONFIG_SB_DMA2		-1
-#endif
-	{SNDCARD_SB, {CONFIG_SB_BASE, CONFIG_SB_IRQ, CONFIG_SB_DMA, CONFIG_SB_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef SB2_BASE
-	{SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#if defined(CONFIG_WAVEFRONT) 
-	{SNDCARD_WAVEFRONT, {WAVEFRONT_BASE, WAVEFRONT_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_MAUI
-	{SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_MPU401
-	{SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#ifdef MPU2_BASE
-	{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#ifdef MPU3_BASE
-	{SNDCARD_MPU401, {MPU3_BASE, MPU3_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_UART6850
-	{SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_SB
-#ifdef CONFIG_SB_MPU_BASE
-	{SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-#endif
-
-#ifdef CONFIG_SOUND_GUS
-#ifndef CONFIG_GUS_DMA2
-#define CONFIG_GUS_DMA2 CONFIG_GUS_DMA
-#endif
-#ifdef CONFIG_GUS16
-	{SNDCARD_GUS16, {CONFIG_GUS16_BASE, CONFIG_GUS16_IRQ, CONFIG_GUS16_DMA, -1}, SND_DEFAULT_ENABLE},
-#endif
-	{SNDCARD_GUS, {CONFIG_GUS_BASE, CONFIG_GUS_IRQ, CONFIG_GUS_DMA, CONFIG_GUS_DMA2}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_YM3812
-	{SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_VMIDI
-	{SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE},
-#endif
-
-#ifdef CONFIG_SOUND_VIDC
-	{ SNDCARD_VIDC, {0, 0, 0, 0}, SND_DEFAULT_ENABLE },
-#endif
-
-#ifdef CONFIG_SOUND_WAVEARTIST
-	{ SNDCARD_WAVEARTIST, { CONFIG_WAVEARTIST_BASE, CONFIG_WAVEARTIST_IRQ, CONFIG_WAVEARTIST_DMA, CONFIG_WAVEARTIST_DMA2 }, SND_DEFAULT_ENABLE },
-#endif
-	{0, {0}, 0}
-};
-
-int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info);
-static int max_sound_cards =  sizeof(snd_installed_cards) / sizeof (struct card_info);
-
-#if defined(MODULE)
-int trace_init = 0;
-#else
-int trace_init = 1;
-#endif
 
 #else
 extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs;
@@ -689,30 +377,16 @@
 extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths;
 extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
 extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; extern int num_sound_timers;
-
-extern struct driver_info sound_drivers[];
-extern int num_sound_drivers;
-extern struct card_info snd_installed_cards[];
-extern int num_sound_cards;
-
-extern int trace_init;
 #endif	/* _DEV_TABLE_C_ */
-void sndtable_init(void);
+void setup_cards(void);
 int sndtable_get_cardcount (void);
-struct address_info *sound_getconf(int card_type);
 void sound_chconf(int card_type, int ioaddr, int irq, int dma);
 int snd_find_driver(int type);
-void sound_unload_drivers(void);
 void sound_unload_driver(int type);
 int sndtable_identify_card(char *name);
 
-#if FIXED_FOR_2_4_0
-void sound_setup (char *str, int *ints);
-#endif
-
 extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
 int sndtable_probe (int unit, struct address_info *hw_config);
-int sndtable_init_card (int unit, struct address_info *hw_config);
 int sndtable_start_card (int unit, struct address_info *hw_config);
 void sound_timer_init (struct sound_lowlev_timer *t, char *name);
 void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus.h linux/drivers/sound/gus.h
--- v2.3.49/linux/drivers/sound/gus.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/gus.h	Tue Mar  7 13:40:24 2000
@@ -0,0 +1,30 @@
+/*
+ * gus.h
+ *
+ * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
+ *
+ */
+
+#include "ad1848.h"
+
+/*	From gus_card.c */
+int gus_set_midi_irq(int num);
+void gusintr(int irq, void *dev_id, struct pt_regs * dummy);
+
+/*	From gus_wave.c */
+int gus_wave_detect(int baseaddr);
+void gus_wave_init(struct address_info *hw_config);
+void gus_wave_unload (struct address_info *hw_config);
+void gus_voice_irq(void);
+void gus_write8(int reg, unsigned int data);
+void guswave_dma_irq(void);
+void gus_delay(void);
+int gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg);
+void gus_timer_command (unsigned int addr, unsigned int val);
+
+/*	From gus_midi.c */
+void gus_midi_init(struct address_info *hw_config);
+void gus_midi_interrupt(int dummy);
+
+/*	From ics2101.c */
+int ics2101_mixer_init(void);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v2.3.49/linux/drivers/sound/gus_card.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/gus_card.c	Tue Mar  7 13:40:24 2000
@@ -2,18 +2,13 @@
  * sound/gus_card.c
  *
  * Detection routine for the Gravis Ultrasound.
- */
- 
-/*
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-/*
+ *
  * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
  *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
+ * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups.
  *
  * Status:
  *              Tested... 
@@ -21,11 +16,13 @@
       
  
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 
+#include "gus.h"
 #include "gus_hw.h"
 
 void            gusintr(int irq, void *dev_id, struct pt_regs *dummy);
@@ -36,13 +33,12 @@
 extern int      gus_pcm_volume;
 extern int      have_gus_max;
 int             gus_pnp_flag = 0;
-#ifdef CONFIG_GUS16
+#ifdef CONFIG_SOUND_GUS16
 static int      db16 = 0;	/* Has a Gus16 AD1848 on it */
 #endif
 
-void attach_gus_card(struct address_info *hw_config)
+static void __init attach_gus(struct address_info *hw_config)
 {
-
 	gus_wave_init(hw_config);
 
 	request_region(hw_config->io_base, 16, "GUS");
@@ -57,9 +53,10 @@
 	if(request_irq(hw_config->irq, gusintr, 0,  "Gravis Ultrasound", hw_config)<0)
 		printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
 
+	return;
 }
 
-int probe_gus(struct address_info *hw_config)
+static int __init probe_gus(struct address_info *hw_config)
 {
 	int             irq;
 	int             io_addr;
@@ -102,10 +99,11 @@
 					  }
 #endif
 
+	printk("NO GUS card found !\n");
 	return 0;
 }
 
-void unload_gus(struct address_info *hw_config)
+static void __exit unload_gus(struct address_info *hw_config)
 {
 	DDB(printk("unload_gus(%x)\n", hw_config->io_base));
 
@@ -128,13 +126,13 @@
 
 	sti();
 
-#ifdef CONFIG_GUSMAX
+#ifdef CONFIG_SOUND_GUSMAX
 	if (have_gus_max) {
 		struct address_info *hw_config = dev_id;
 		adintr(irq, (void *)hw_config->slots[1], NULL);
 	}
 #endif
-#ifdef CONFIG_GUS16
+#ifdef CONFIG_SOUND_GUS16
 	if (db16) {
 		struct address_info *hw_config = dev_id;
 		adintr(irq, (void *)hw_config->slots[3], NULL);
@@ -170,14 +168,14 @@
  *	Some extra code for the 16 bit sampling option
  */
 
-#ifdef CONFIG_GUS16
+#ifdef CONFIG_SOUND_GUS16
 
-int probe_gus_db16(struct address_info *hw_config)
+static int __init probe_gus_db16(struct address_info *hw_config)
 {
 	return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
 }
 
-void attach_gus_db16(struct address_info *hw_config)
+static void __init attach_gus_db16(struct address_info *hw_config)
 {
 	gus_pcm_volume = 100;
 	gus_wave_volume = 90;
@@ -189,7 +187,7 @@
 					  hw_config->osp);
 }
 
-void unload_gus_db16(struct address_info *hw_config)
+static void __exit unload_gus_db16(struct address_info *hw_config)
 {
 
 	ad1848_unload(hw_config->io_base,
@@ -200,27 +198,25 @@
 }
 #endif
 
+static int gus16 = 0;
+#ifdef CONFIG_SOUND_GUSMAX
+static int no_wave_dma = 0;/* Set if no dma is to be used for the
+                                   wave table (GF1 chip) */
+#endif
 
 
-#ifdef MODULE
-
-static struct address_info config;
-
 /*
  *    Note DMA2 of -1 has the right meaning in the GUS driver as well
  *      as here. 
  */
 
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma16 = -1;	/* Set this for modules that need it */
-int             type = 0;	/* 1 for PnP */
-int             gus16 = 0;
-#ifdef CONFIG_GUSMAX
-static int      no_wave_dma = 0;/* Set if no dma is to be used for the 
-				   wave table (GF1 chip) */
-#endif
+static struct address_info cfg;
+
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata dma16 = -1;	/* Set this for modules that need it */
+static int __initdata type = 0;		/* 1 for PnP */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -228,54 +224,73 @@
 MODULE_PARM(dma16, "i");
 MODULE_PARM(type, "i");
 MODULE_PARM(gus16, "i");
-#ifdef CONFIG_GUSMAX
+#ifdef CONFIG_SOUND_GUSMAX
 MODULE_PARM(no_wave_dma, "i");
 #endif
-#ifdef CONFIG_GUS16
+#ifdef CONFIG_SOUND_GUS16
 MODULE_PARM(db16, "i");
 #endif
 
-int init_module(void)
+static int __init init_gus(void)
 {
 	printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
-	if (io == -1 || dma == -1 || irq == -1)
-	{
+	cfg.io_base = io;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.dma2 = dma16;
+	cfg.card_subtype = type;
+#ifdef CONFIG_SOUND_GUSMAX
+	gus_no_wave_dma = no_wave_dma;
+#endif
+
+	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
 		printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n");
 		return -EINVAL;
 	}
-	config.io_base = io;
-	config.irq = irq;
-	config.dma = dma;
-	config.dma2 = dma16;
-	config.card_subtype = type;
-	
-#ifdef CONFIG_GUSMAX
-	gus_no_wave_dma = no_wave_dma;
-#endif
 
-#if defined(CONFIG_GUS16)
-	if (probe_gus_db16(&config) && gus16)
-	{
-		attach_gus_db16(&config);
+#ifdef CONFIG_SOUND_GUS16
+	if (probe_gus_db16(&cfg) && gus16) {
+		/* FIXME: This can't work, can it ? -- Christoph */
+		attach_gus_db16(&cfg);
 		db16 = 1;
 	}	
 #endif
-	if (probe_gus(&config) == 0)
+	if (!probe_gus(&cfg))
 		return -ENODEV;
-	attach_gus_card(&config);
+	attach_gus(&cfg);
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_gus(void)
 {
-#if defined(CONFIG_GUS16)
+#ifdef CONFIG_SOUND_GUS16
 	if (db16)
-		unload_gus_db16(&config);
+		unload_gus_db16(&cfg);
 #endif
-	unload_gus(&config);
+	unload_gus(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_gus);
+module_exit(cleanup_gus);
+
+#ifndef MODULE
+static int __init setup_gus(char *str)
+{
+	/* io, irq, dma, dma2 */
+	int ints[5];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma16	= ints[4];
+
+	return 1;
+}
+
+__setup("gus=", setup_gus);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v2.3.49/linux/drivers/sound/gus_midi.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/gus_midi.c	Tue Mar  7 13:40:24 2000
@@ -2,8 +2,8 @@
  * sound/gus2_midi.c
  *
  * The low level driver for the GUS Midi Interface.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -11,6 +11,8 @@
  * for more info.
  */
 #include "sound_config.h"
+
+#include "gus.h"
 #include "gus_hw.h"
 
 static int      midi_busy = 0, input_opened = 0;
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c
--- v2.3.49/linux/drivers/sound/gus_vol.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/gus_vol.c	Tue Mar  7 13:40:24 2000
@@ -1,8 +1,8 @@
 
 /*
  * gus_vol.c - Compute volume for GUS.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -10,6 +10,8 @@
  * for more info.
  */
 #include "sound_config.h"
+
+#include "gus.h"
 #include "gus_linearvol.h"
 
 #define GUS_VOLUME	gus_wave_volume
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.3.49/linux/drivers/sound/gus_wave.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/gus_wave.c	Tue Mar  7 13:40:24 2000
@@ -2,15 +2,15 @@
  * sound/gus_wave.c
  *
  * Driver for the Gravis UltraSound wave table synth.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Thomas Sailer    : ioctl code reworked (vmalloc/vfree removed)
  * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
  *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
@@ -23,6 +23,8 @@
 
 #include "sound_config.h"
 #include <linux/ultrasound.h>
+
+#include "gus.h"
 #include "gus_hw.h"
 
 #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
@@ -3012,7 +3014,7 @@
 			model_num = "MAX";
 			gus_type = 0x40;
 			mixer_type = CS4231;
-#ifdef CONFIG_GUSMAX
+#ifdef CONFIG_SOUND_GUSMAX
 			{
 				unsigned char   max_config = 0x40;	/* Codec enable */
 
@@ -3164,7 +3166,7 @@
 
 void gus_wave_unload(struct address_info *hw_config)
 {
-#ifdef CONFIG_GUSMAX
+#ifdef CONFIG_SOUND_GUSMAX
 	if (have_gus_max)
 	{
 		ad1848_unload(gus_base + 0x10c,
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c
--- v2.3.49/linux/drivers/sound/ics2101.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/ics2101.c	Tue Mar  7 13:40:24 2000
@@ -2,20 +2,22 @@
  * sound/ics2101.c
  *
  * Driver for the ICS2101 mixer of GUS v3.7.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  */
 #include "sound_config.h"
 
 #include <linux/ultrasound.h>
+
+#include "gus.h"
 #include "gus_hw.h"
 
 #define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.3.49/linux/drivers/sound/mad16.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/mad16.c	Tue Mar  7 13:40:24 2000
@@ -1,14 +1,7 @@
 /*
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-/*
- * sound/mad16.c
+ * mad16.c
  *
  * Initialization code for OPTi MAD16 compatible audio chips. Including
  *
@@ -72,22 +65,23 @@
  *
  *	Paul Grayson		Added support for Midi on later Mozart cards.
  *								25-Nov-1999
+ *	Christoph Hellwig	Adapted to module_init/module_exit.
  */
 
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef MODULE
-#define MAD16_CDSEL   mad16_cdsel
-#define MAD16_CONF    mad16_conf
+#include "ad1848.h"
+#include "sb.h"
+#include "mpu401.h"
 
 static int      mad16_conf;
 static int      mad16_cdsel;
 
-#endif
-
-#include "sb.h"
-
 static int      already_initialized = 0;
 
 #define C928	1
@@ -222,7 +216,7 @@
 	restore_flags(flags);
 }
 
-static int detect_c930(void)
+static int __init detect_c930(void)
 {
 	unsigned char   tmp = mad_read(MC1_PORT);
 
@@ -295,7 +289,7 @@
 	return 1;
 }
 
-static int detect_mad16(void)
+static int __init detect_mad16(void)
 {
 	unsigned char tmp, tmp2, bit;
 	int i, port;
@@ -346,7 +340,7 @@
 	return 1;		/* Bingo */
 }
 
-static int wss_init(struct address_info *hw_config)
+static int __init wss_init(struct address_info *hw_config)
 {
 	int ad_flags = 0;
 
@@ -397,7 +391,7 @@
 	return 1;
 }
 
-static int init_c930(struct address_info *hw_config)
+static int __init init_c930(struct address_info *hw_config)
 {
 	unsigned char cfg = 0;
 
@@ -457,7 +451,7 @@
 	return wss_init(hw_config);
 }
 
-static int chip_detect(void)
+static int __init chip_detect(void)
 {
 	int i;
 
@@ -536,7 +530,7 @@
 	return 1;
 }
 
-int probe_mad16(struct address_info *hw_config)
+static int __init probe_mad16(struct address_info *hw_config)
 {
 	int i;
 	static int valid_ports[] = 
@@ -646,7 +640,7 @@
 	return 1;
 }
 
-void attach_mad16(struct address_info *hw_config)
+static void __init attach_mad16(struct address_info *hw_config)
 {
 
 	static char     interrupt_bits[12] = {
@@ -720,7 +714,7 @@
 	request_region(hw_config->io_base, 4, "MAD16 WSS config");
 }
 
-void attach_mad16_mpu(struct address_info *hw_config)
+static void __init attach_mad16_mpu(struct address_info *hw_config)
 {
 #ifdef CONFIG_MAD16_OLDCARD
 
@@ -742,7 +736,7 @@
 	attach_uart401(hw_config);
 }
 
-int probe_mad16_mpu(struct address_info *hw_config)
+static int __init probe_mad16_mpu(struct address_info *hw_config)
 {
 	static int mpu_attached = 0;
 	static int valid_ports[] = {
@@ -898,7 +892,7 @@
 	return probe_uart401(hw_config);
 }
 
-void unload_mad16(struct address_info *hw_config)
+static void __exit unload_mad16(struct address_info *hw_config)
 {
 	ad1848_unload(hw_config->io_base + 4,
 			hw_config->irq,
@@ -908,8 +902,7 @@
 	sound_unload_audiodev(hw_config->slots[0]);
 }
 
-void
-unload_mad16_mpu(struct address_info *hw_config)
+static void __exit unload_mad16_mpu(struct address_info *hw_config)
 {
 #ifdef CONFIG_MAD16_OLDCARD
 	if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
@@ -922,21 +915,23 @@
 	unload_uart401(hw_config);
 }
 
-#ifdef MODULE
+static struct address_info cfg;
+static struct address_info cfg_mpu;
 
-int		mpu_io = 0;
-int		mpu_irq = 0;
-int             io = -1;
-int             dma = -1;
-int             dma16 = -1;	/* Set this for modules that need it */
-int             irq = -1;
-
-int             cdtype = 0;
-int             cdirq = 0;
-int             cdport = 0x340;
-int             cddma = -1;
-int             opl4 = 0;
-int             joystick = 0;
+static int found_mpu;
+
+static int __initdata mpu_io = 0;
+static int __initdata mpu_irq = 0;
+static int __initdata io = -1;
+static int __initdata dma = -1;
+static int __initdata dma16 = -1; /* Set this for modules that need it */
+static int __initdata irq = -1;
+static int __initdata cdtype = 0;
+static int __initdata cdirq = 0;
+static int __initdata cdport = 0x340;
+static int __initdata cddma = -1;
+static int __initdata opl4 = 0;
+static int __initdata joystick = 0;
 
 MODULE_PARM(mpu_io, "i");
 MODULE_PARM(mpu_irq, "i");
@@ -952,18 +947,13 @@
 MODULE_PARM(joystick,"i");
 MODULE_PARM(debug,"i");
 
-EXPORT_NO_SYMBOLS;
-
-static int found_mpu;
-
-
-static int dma_map[2][8] =
+static int __initdata dma_map[2][8] =
 {
 	{0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
 	{0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
 };
 
-static int irq_map[16] =
+static int __initdata irq_map[16] =
 {
 	0x00, -1, -1, 0x0A,
 	-1, 0x04, -1, 0x08,
@@ -971,20 +961,12 @@
 	-1, -1, -1, -1
 };
 
-struct address_info config;
-struct address_info config_mpu;
-
-int init_module(void)
+static int __init init_mad16(void)
 {
 	int dmatype = 0;
 
 	printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
-	if (io == -1 || dma == -1 || irq == -1)
-	{
-		printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
-		return -EINVAL;
-	}
 	printk(KERN_INFO "CDROM ");
 	switch (cdtype)
 	{
@@ -1089,33 +1071,61 @@
                 printk("disabled.\n");
         }
 
-	config.io_base = io;
-	config.irq = irq;
-	config.dma = dma;
-	config.dma2 = dma16;
+	cfg.io_base = io;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.dma2 = dma16;
 
-	if (!probe_mad16(&config))
+	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
+		printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
+		return -EINVAL;
+	}
+	
+	if (!probe_mad16(&cfg))
 		return -ENODEV;
 
-	config_mpu.io_base = mpu_io;
-	config_mpu.irq = mpu_irq;
-	attach_mad16(&config);
+	cfg_mpu.io_base = mpu_io;
+	cfg_mpu.irq = mpu_irq;
+
+	attach_mad16(&cfg);
 
-	found_mpu = probe_mad16_mpu(&config_mpu);
+	found_mpu = probe_mad16_mpu(&cfg_mpu);
 
 	if (found_mpu)
-		attach_mad16_mpu(&config_mpu);
+		attach_mad16_mpu(&cfg_mpu);
 
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_mad16(void)
 {
 	if (found_mpu)
-		unload_mad16_mpu(&config_mpu);
-	unload_mad16(&config);
+		unload_mad16_mpu(&cfg_mpu);
+	unload_mad16(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_mad16);
+module_exit(exit_mad16);
+
+#ifndef MODULE
+static int __init setup_mad16(char *str)
+{
+        /* io, irq */
+	int ints[7];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma16	= ints[4];
+	mpu_io	= ints[5];
+	mpu_irq = ints[6];
+
+	return 1;
+}
+
+__setup("mad16=", setup_mad16);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.3.49/linux/drivers/sound/maui.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/maui.c	Tue Mar  7 13:40:24 2000
@@ -2,8 +2,8 @@
  * sound/maui.c
  *
  * The low level driver for Turtle Beach Maui and Tropez.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -13,6 +13,7 @@
  *	Changes:
  *		Alan Cox		General clean up, use kernel IRQ 
  *					system
+ *		Christoph Hellwig	Adapted to module_init/module_exit
  *
  *	Status:
  *		Andrew J. Kroll		Tested 06/01/1999 with:
@@ -32,6 +33,8 @@
 #include "soundmodule.h"
 #include "sound_firmware.h"
 
+#include "mpu401.h"
+
 static int      maui_base = 0x330;
 
 static volatile int irq_ok = 0;
@@ -62,19 +65,14 @@
 	 */
 
 	for (i = 0; i < 100; i++)
-	{
 		if (inb(HOST_STAT_PORT) & mask)
-		{
 			return 1;
-		}
-	}
 
 	/*
 	 * Wait up to 15 seconds with sleeping
 	 */
 
-	for (i = 0; i < 150; i++)
-	{
+	for (i = 0; i < 150; i++) {
 		if (inb(HOST_STAT_PORT) & mask)
 			return 1;
 		current->state = TASK_INTERRUPTIBLE;
@@ -94,8 +92,7 @@
 
 static int maui_write(unsigned char data)
 {
-	if (maui_wait(STAT_TX_AVAIL))
-	{
+	if (maui_wait(STAT_TX_AVAIL)) {
 		outb((data), HOST_DATA_PORT);
 		return 1;
 	}
@@ -116,56 +113,45 @@
 
 	printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
 
-	for (i = 0; i < maui_osLen; i++)
-	{
-		if (maui_os[i] != '\r')
-		{
-			if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n')))
-			{
+	for (i = 0; i < maui_osLen; i++) {
+		if (maui_os[i] != '\r') {
+			if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
 				skip = 0;
 
 				if (maui_os[i] == '\n')
 					eol_seen = skip = 1;
-				else if (maui_os[i] == 'S')
-				{
+				else if (maui_os[i] == 'S') {
 					if (maui_os[i + 1] == '8')
 						done = 1;
 					if (!maui_write(0xF1))
 						goto failure;
 					if (!maui_write('S'))
 						goto failure;
-				}
-				else
-				{
+				} else {
 					if (!maui_write(maui_os[i]))
 						goto failure;
 				}
 
-				if (eol_seen)
-				{
+				if (eol_seen) {
 					int c = 0;
 					int n;
 
 					eol_seen = 0;
 
-					for (n = 0; n < 2; n++)
-					{
-						if (maui_wait(STAT_RX_AVAIL))
-						{
+					for (n = 0; n < 2; n++) {
+						if (maui_wait(STAT_RX_AVAIL)) {
 							c = inb(HOST_DATA_PORT);
 							break;
 						}
 					}
-					if (c != 0x80)
-					{
+					if (c != 0x80) {
 						printk("Download not acknowledged\n");
 						return 0;
 					}
 					else if (!(lines++ % 10))
 						printk(".");
 
-					if (done)
-					{
+					if (done) {
 						printk("\n");
 						printk(KERN_INFO "Download complete\n");
 						return 1;
@@ -181,15 +167,11 @@
 	return 0;
 }
 
-static int maui_init(int irq)
+static int __init maui_init(int irq)
 {
-#ifdef CONFIG_SMP
-	int i;
-#endif	
 	unsigned char bits;
 
-	switch (irq)
-	{
+	switch (irq) {
 		case 9:
 			bits = 0x00;
 			break;
@@ -215,10 +197,13 @@
 	outb((0xD0), HOST_CTRL_PORT);	/* Cause interrupt */
 
 #ifdef CONFIG_SMP
-	for (i = 0; i < 1000000 && !irq_ok; i++);
-
-	if (!irq_ok)
-		return 0;
+	{
+		int i;
+		for (i = 0; i < 1000000 && !irq_ok; i++)
+			;
+		if (!irq_ok)
+			return 0;
+	}
 #endif
 	outb((0x80), HOST_CTRL_PORT);	/* Leave reset */
 
@@ -233,8 +218,7 @@
 
 	maui_write(0xf0);
 	maui_write(1);
-	if (maui_read() != 0x80)
-	{
+	if (maui_read() != 0x80) {
 		maui_write(0xf0);
 		maui_write(1);
 		if (maui_read() != 0x80)
@@ -244,14 +228,11 @@
 	return 1;
 }
 
-static int maui_short_wait(int mask)
-{
+static int maui_short_wait(int mask) {
 	int i;
 
-	for (i = 0; i < 1000; i++)
-	{
-		if (inb(HOST_STAT_PORT) & mask)
-		{
+	for (i = 0; i < 1000; i++) {
+		if (inb(HOST_STAT_PORT) & mask) {
 			return 1;
 		}
 	}
@@ -274,8 +255,7 @@
 	{
 		  printk(KERN_WARNING "Maui: Unknown patch format\n");
 	}
-	if (count < hdr_size)
-	{
+	if (count < hdr_size) {
 /*		  printk("Maui error: Patch header too short\n");*/
 		  return -EINVAL;
 	}
@@ -289,16 +269,14 @@
 	if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
 		return -EFAULT;
 
-	if (count < header.len)
-	{
+	if (count < header.len) {
 		  printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
 		  header.len = count;
 	}
 	left = header.len;
 	src_offs = 0;
 
-	for (i = 0; i < left; i++)
-	{
+	for (i = 0; i < left; i++) {
 		unsigned char   data;
 
 		if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])))
@@ -310,8 +288,7 @@
 			return -EIO;
 	}
 
-	if ((i = maui_read()) != 0x80)
-	{
+	if ((i = maui_read()) != 0x80) {
 		if (i != -1)
 			printk("Maui: Error status %02x\n", i);
 		return -EIO;
@@ -319,7 +296,7 @@
 	return 0;
 }
 
-int probe_maui(struct address_info *hw_config)
+static int __init probe_maui(struct address_info *hw_config)
 {
 	int i;
 	int tmp1, tmp2, ret;
@@ -337,55 +314,46 @@
 	 * Initialize the processor if necessary
 	 */
 
-	if (maui_osLen > 0)
-	{
+	if (maui_osLen > 0) {
 		if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
 			!maui_write(0x9F) ||	/* Report firmware version */
 			!maui_short_wait(STAT_RX_AVAIL) ||
 			maui_read() == -1 || maui_read() == -1)
-			if (!maui_init(hw_config->irq))
-			{
+			if (!maui_init(hw_config->irq)) {
 				free_irq(hw_config->irq, NULL);
 				return 0;
 			}
 	}
-	if (!maui_write(0xCF))	/* Report hardware version */
-	{
+	if (!maui_write(0xCF))	/* Report hardware version */ {
 		printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
 		free_irq(hw_config->irq, NULL);
 		return 0;
 	}
-	if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
-	{
+	if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
 		printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
 		free_irq(hw_config->irq, NULL);
 		return 0;
 	}
-	if (tmp1 == 0xff || tmp2 == 0xff)
-	{
+	if (tmp1 == 0xff || tmp2 == 0xff) {
 		free_irq(hw_config->irq, NULL);
 		return 0;
 	}
-	if (trace_init)
-		printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
+	printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
 
 	if (!maui_write(0x9F))	/* Report firmware version */
 		return 0;
 	if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
 		return 0;
 
-	if (trace_init)
-		printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
+	printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
 
 	if (!maui_write(0x85))	/* Report free DRAM */
 		return 0;
 	tmp1 = 0;
-	for (i = 0; i < 4; i++)
-	{
+	for (i = 0; i < 4; i++) {
 		tmp1 |= maui_read() << (7 * i);
 	}
-	if (trace_init)
-		printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
+	printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
 
 	for (i = 0; i < 1000; i++)
 		if (probe_mpu401(hw_config))
@@ -399,7 +367,7 @@
 	return ret;
 }
 
-void attach_maui(struct address_info *hw_config)
+static void __init attach_maui(struct address_info *hw_config)
 {
 	int this_dev;
 
@@ -409,8 +377,7 @@
 	hw_config->name = "Maui";
 	attach_mpu401(hw_config);
 
-	if (hw_config->slots[1] != -1)	/* The MPU401 driver installed itself */
-	{
+	if (hw_config->slots[1] != -1)	/* The MPU401 driver installed itself */ {
 		struct synth_operations *synth;
 
 		this_dev = hw_config->slots[1];
@@ -423,17 +390,15 @@
 		synth = midi_devs[this_dev]->converter;
 		synth->id = "MAUI";
 
-		if (synth != NULL)
-		{
+		if (synth != NULL) {
 			orig_load_patch = synth->load_patch;
 			synth->load_patch = &maui_load_patch;
-		}
-		else
+		} else
 			printk(KERN_ERR "Maui: Can't install patch loader\n");
 	}
 }
 
-void unload_maui(struct address_info *hw_config)
+static void __exit unload_maui(struct address_info *hw_config)
 {
 	int irq = hw_config->irq;
 	release_region(hw_config->io_base + 2, 6);
@@ -445,37 +410,33 @@
 		free_irq(irq, NULL);
 }
 
-#ifdef MODULE
-
-MODULE_PARM(io,"i");
-MODULE_PARM(irq,"i");
-
-EXPORT_NO_SYMBOLS;
+static int fw_load = 0;
 
-int io = -1;
-int irq = -1;
+static struct address_info cfg;
 
-static int fw_load = 0;
+static int __initdata io = -1;
+static int __initdata irq = -1;
 
-struct address_info cfg;
+MODULE_PARM(io,"i");
+MODULE_PARM(irq,"i");
 
 /*
  *	Install a Maui card. Needs mpu401 loaded already.
  */
 
-int init_module(void)
+static int __init init_maui(void)
 {
 	printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
-	if (io == -1 || irq == -1)
-	{
+
+	cfg.io_base = io;
+	cfg.irq = irq;
+
+	if (cfg.io_base == -1 || cfg.irq == -1) {
 		printk(KERN_INFO "maui: irq and io must be set.\n");
 		return -EINVAL;
 	}
-	cfg.io_base = io;
-	cfg.irq = irq;
 
-	if (maui_os == NULL)
-	{
+	if (maui_os == NULL) {
 		fw_load = 1;
 		maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
 	}
@@ -486,11 +447,30 @@
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_maui(void)
 {
 	if (fw_load && maui_os)
 		vfree(maui_os);
 	unload_maui(&cfg);
 	SOUND_LOCK_END;
 }
-#endif /* MODULE */
+
+module_init(init_maui);
+module_exit(cleanup_maui);
+
+#ifndef MODULE
+static int __init setup_maui(char *str)
+{
+        /* io, irq */
+	int ints[3];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io = ints[1];
+	irq = ints[2];
+
+	return 1;
+}
+
+__setup("maui=", setup_maui);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v2.3.49/linux/drivers/sound/mpu401.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/mpu401.c	Tue Mar  7 13:40:24 2000
@@ -15,6 +15,7 @@
  * Alan Cox		modularisation, use normal request_irq, use dev_id
  */
 
+#include <linux/init.h>
 #include <linux/module.h>
 
 #define USE_SEQ_MACROS
@@ -24,7 +25,7 @@
 #include "soundmodule.h"
 
 #include "coproc.h"
-
+#include "mpu401.h"
 
 static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
 
@@ -910,7 +911,7 @@
 
 static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
 
-static void mpu401_chk_version(int n, struct mpu_config *devc)
+static void __init mpu401_chk_version(int n, struct mpu_config *devc)
 {
 	int tmp;
 	unsigned long flags;
@@ -941,7 +942,7 @@
 	restore_flags(flags);
 }
 
-void attach_mpu401(struct address_info *hw_config)
+void __init attach_mpu401(struct address_info *hw_config)
 {
 	unsigned long flags;
 	char revision_char;
@@ -1164,7 +1165,7 @@
 
 }
 
-int probe_mpu401(struct address_info *hw_config)
+int __init probe_mpu401(struct address_info *hw_config)
 {
 	int ok = 0;
 	struct mpu_config tmp_devc;
@@ -1197,7 +1198,7 @@
 	return ok;
 }
 
-void unload_mpu401(struct address_info *hw_config)
+void __exit unload_mpu401(struct address_info *hw_config)
 {
 	void *p;
 	int n=hw_config->slots[1];
@@ -1659,7 +1660,7 @@
 	}
 }
 
-static int mpu_timer_init(int midi_dev)
+static int __init mpu_timer_init(int midi_dev)
 {
 	struct mpu_config *devc;
 	int n;
@@ -1713,39 +1714,56 @@
 EXPORT_SYMBOL(intchk_mpu401);
 EXPORT_SYMBOL(mpuintr);
 
-#ifdef MODULE
+static struct address_info cfg;
+
+static int __initdata io = -1;
+static int __initdata irq = -1;
 
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
 
-int             io = -1;
-int             irq = -1;
-struct address_info hw;
-
-int init_module(void)
+int init_mpu401(void)
 {
 	/* Can be loaded either for module use or to provide functions
 	   to others */
-	if (io != -1 && irq != -1)
-	{
-		hw.irq = irq;
-		hw.io_base = io;
-		if (probe_mpu401(&hw) == 0)
-			return -ENODEV;
-		attach_mpu401(&hw);
+	cfg.irq = irq;
+	cfg.io_base = io;
+	
+	if (cfg.io_base != -1 && cfg.irq != -1) {
+		printk(KERN_WARNING "mpu401: need io and irq !");
+		return -ENODEV;
 	}
+	
+	if (probe_mpu401(&cfg) == 0)
+		return -ENODEV;
+	attach_mpu401(&cfg);
+
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+void cleanup_mpu401(void)
 {
-	if (io != -1 && irq != -1)
-	{
-		unload_mpu401(&hw);
-	}
-	/*  FREE SYMTAB */
+	unload_mpu401(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_mpu401);
+module_exit(cleanup_mpu401);
+
+#ifndef MODULE
+static int __init setup_mpu401(char *str)
+{
+        /* io, irq */
+	int ints[3];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io = ints[1];
+	irq = ints[2];
+
+	return 1;
+}
+
+__setup("mpu401=", setup_mpu401);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/mpu401.h linux/drivers/sound/mpu401.h
--- v2.3.49/linux/drivers/sound/mpu401.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/mpu401.h	Tue Mar  7 13:40:24 2000
@@ -0,0 +1,21 @@
+/*
+ *	uart401.h 
+ *
+ * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
+ *
+ */
+
+/*	From uart401.c */
+int probe_uart401 (struct address_info *hw_config);
+void attach_uart401 (struct address_info *hw_config);
+void unload_uart401 (struct address_info *hw_config);
+
+void uart401intr (int irq, void *dev_id, struct pt_regs * dummy);
+
+/*	From mpu401.c */
+int probe_mpu401(struct address_info *hw_config);
+void attach_mpu401(struct address_info * hw_config);
+void unload_mpu401(struct address_info *hw_info);
+
+int intchk_mpu401(void *dev_id);
+void mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c
--- v2.3.49/linux/drivers/sound/nm256_audio.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/nm256_audio.c	Tue Mar  7 13:40:24 2000
@@ -15,6 +15,7 @@
 
 #define __NO_VERSION__
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pm.h>
 #include "sound_config.h"
@@ -1639,8 +1640,6 @@
 
 EXPORT_SYMBOL(init_nm256);
 
-#ifdef MODULE
-
 static int loaded = 0;
 
 MODULE_PARM (usecache, "i");
@@ -1648,8 +1647,7 @@
 MODULE_PARM (nm256_debug, "i");
 MODULE_PARM (force_load, "i");
 
-int
-init_module (void)
+static int __init do_init_nm256(void)
 {
     nmcard_list = NULL;
     printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n");
@@ -1663,8 +1661,7 @@
 	return -ENODEV;
 }
 
-void
-cleanup_module (void)
+static void __exit cleanup_nm256 (void)
 {
     if (loaded) {
 	struct nm256_info *card;
@@ -1688,8 +1685,10 @@
     }
     pm_unregister_all (&handle_pm_event);
 }
-#endif
-
+
+module_init(do_init_nm256);
+module_exit(cleanup_nm256);
+
 /*
  * Local variables:
  *  c-basic-offset: 4
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v2.3.49/linux/drivers/sound/opl3.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/opl3.c	Tue Mar  7 13:40:24 2000
@@ -3,7 +3,7 @@
  *
  * A low level driver for Yamaha YM3812 and OPL-3 -chips
  *
-*
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -12,14 +12,16 @@
  *
  *
  * Changes
- *	Thomas Sailer   ioctl code reworked (vmalloc/vfree removed)
- *	Alan Cox	modularisation, fixed sound_mem allocs.
+ *	Thomas Sailer   	ioctl code reworked (vmalloc/vfree removed)
+ *	Alan Cox		modularisation, fixed sound_mem allocs.
+ *	Christoph Hellwig	Adapted to module_init/module_exit
  *
  * Status
  *	Believed to work. Badly needs rewriting a bit to support multiple
  *	OPL3 devices.
  */
 
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 
@@ -32,6 +34,7 @@
 #include "soundmodule.h"
 
 #include "opl3.h"
+#include "opl3_hw.h"
 
 #define MAX_VOICE	18
 #define OFFS_4OP	11
@@ -1171,18 +1174,19 @@
 	return me;
 }
 
-#ifdef MODULE
+EXPORT_SYMBOL(opl3_init);
+EXPORT_SYMBOL(opl3_detect);
 
-/*
- *    We provide OPL3 functions.
- */
+static int me;
+
+static int io = -1;
 
-int io = -1;
-int me;
+MODULE_PARM(io, "i");
 
-int init_module (void)
+static int __init init_opl3 (void)
 {
 	printk(KERN_INFO "YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n");
+
 	if (io != -1)	/* User loading pure OPL3 module */
 	{
     		if (check_region(io, 4))
@@ -1195,14 +1199,14 @@
 			return -ENODEV;
 		}
 		me = opl3_init(io, NULL);
-		request_region(io,4,devc->fm_info.name);
+		request_region(io, 4, devc->fm_info.name);
 
 	}
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_opl3(void)
 {
 	if (devc && io != -1)
 	{
@@ -1215,10 +1219,21 @@
 	SOUND_LOCK_END;
 }
 
-MODULE_PARM(io, "i");
+module_init(init_opl3);
+module_exit(cleanup_opl3);
 
-#endif /* MODULE */
+#ifndef MODULE
+static int __init setup_opl3(char *str)
+{
+        /* io  */
+	int ints[2];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io = ints[1];
 
-EXPORT_SYMBOL(opl3_init);
-EXPORT_SYMBOL(opl3_detect);
+	return 1;
+}
 
+__setup("opl3=", setup_opl3);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h
--- v2.3.49/linux/drivers/sound/opl3.h	Tue Sep 30 08:46:45 1997
+++ linux/drivers/sound/opl3.h	Tue Mar  7 13:40:24 2000
@@ -1,244 +1,11 @@
 /*
- *	opl3.h	- Definitions of the OPL-3 registers
- */
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-/*
- *	The OPL-3 mode is switched on by writing 0x01, to the offset 5
- *	of the right side.
- *
- *	Another special register at the right side is at offset 4. It contains
- *	a bit mask defining which voices are used as 4 OP voices.
- *
- *	The percussive mode is implemented in the left side only.
- *
- *	With the above exceptions the both sides can be operated independently.
- *	
- *	A 4 OP voice can be created by setting the corresponding
- *	bit at offset 4 of the right side.
- *
- *	For example setting the rightmost bit (0x01) changes the
- *	first voice on the right side to the 4 OP mode. The fourth
- *	voice is made inaccessible.
- *
- *	If a voice is set to the 2 OP mode, it works like 2 OP modes
- *	of the original YM3812 (AdLib). In addition the voice can 
- *	be connected the left, right or both stereo channels. It can
- *	even be left unconnected. This works with 4 OP voices also.
- *
- *	The stereo connection bits are located in the FEEDBACK_CONNECTION
- *	register of the voice (0xC0-0xC8). In 4 OP voices these bits are
- *	in the second half of the voice.
- */
-
-/*
- *	Register numbers for the global registers
- */
-
-#define TEST_REGISTER				0x01
-#define   ENABLE_WAVE_SELECT		0x20
-
-#define TIMER1_REGISTER				0x02
-#define TIMER2_REGISTER				0x03
-#define TIMER_CONTROL_REGISTER			0x04	/* Left side */
-#define   IRQ_RESET			0x80
-#define   TIMER1_MASK			0x40
-#define   TIMER2_MASK			0x20
-#define   TIMER1_START			0x01
-#define   TIMER2_START			0x02
-
-#define CONNECTION_SELECT_REGISTER		0x04	/* Right side */
-#define   RIGHT_4OP_0			0x01
-#define   RIGHT_4OP_1			0x02
-#define   RIGHT_4OP_2			0x04
-#define   LEFT_4OP_0			0x08
-#define   LEFT_4OP_1			0x10
-#define   LEFT_4OP_2			0x20
-
-#define OPL3_MODE_REGISTER			0x05	/* Right side */
-#define   OPL3_ENABLE			0x01
-#define   OPL4_ENABLE			0x02
-
-#define KBD_SPLIT_REGISTER			0x08	/* Left side */
-#define   COMPOSITE_SINE_WAVE_MODE	0x80		/* Don't use with OPL-3? */
-#define   KEYBOARD_SPLIT		0x40
-
-#define PERCOSSION_REGISTER			0xbd	/* Left side only */
-#define   TREMOLO_DEPTH			0x80
-#define   VIBRATO_DEPTH			0x40
-#define	  PERCOSSION_ENABLE		0x20
-#define   BASSDRUM_ON			0x10
-#define   SNAREDRUM_ON			0x08
-#define   TOMTOM_ON			0x04
-#define   CYMBAL_ON			0x02
-#define   HIHAT_ON			0x01
-
-/*
- *	Offsets to the register banks for operators. To get the
- *	register number just add the operator offset to the bank offset
- *
- *	AM/VIB/EG/KSR/Multiple (0x20 to 0x35)
- */
-#define AM_VIB					0x20
-#define   TREMOLO_ON			0x80
-#define   VIBRATO_ON			0x40
-#define   SUSTAIN_ON			0x20
-#define   KSR				0x10 	/* Key scaling rate */
-#define   MULTIPLE_MASK		0x0f	/* Frequency multiplier */
-
- /*
-  *	KSL/Total level (0x40 to 0x55)
-  */
-#define KSL_LEVEL				0x40
-#define   KSL_MASK			0xc0	/* Envelope scaling bits */
-#define   TOTAL_LEVEL_MASK		0x3f	/* Strength (volume) of OP */
-
-/*
- *	Attack / Decay rate (0x60 to 0x75)
- */
-#define ATTACK_DECAY				0x60
-#define   ATTACK_MASK			0xf0
-#define   DECAY_MASK			0x0f
-
-/*
- * Sustain level / Release rate (0x80 to 0x95)
- */
-#define SUSTAIN_RELEASE				0x80
-#define   SUSTAIN_MASK			0xf0
-#define   RELEASE_MASK			0x0f
-
-/*
- * Wave select (0xE0 to 0xF5)
- */
-#define WAVE_SELECT			0xe0
-
-/*
- *	Offsets to the register banks for voices. Just add to the
- *	voice number to get the register number.
- *
- *	F-Number low bits (0xA0 to 0xA8).
- */
-#define FNUM_LOW				0xa0
-
-/*
- *	F-number high bits / Key on / Block (octave) (0xB0 to 0xB8)
- */
-#define KEYON_BLOCK					0xb0
-#define	  KEYON_BIT				0x20
-#define	  BLOCKNUM_MASK				0x1c
-#define   FNUM_HIGH_MASK			0x03
-
-/*
- *	Feedback / Connection (0xc0 to 0xc8)
- *
- *	These registers have two new bits when the OPL-3 mode
- *	is selected. These bits controls connecting the voice
- *	to the stereo channels. For 4 OP voices this bit is
- *	defined in the second half of the voice (add 3 to the
- *	register offset).
- *
- *	For 4 OP voices the connection bit is used in the
- *	both halves (gives 4 ways to connect the operators).
- */
-#define FEEDBACK_CONNECTION				0xc0
-#define   FEEDBACK_MASK				0x0e	/* Valid just for 1st OP of a voice */
-#define   CONNECTION_BIT			0x01
-/*
- *	In the 4 OP mode there is four possible configurations how the
- *	operators can be connected together (in 2 OP modes there is just
- *	AM or FM). The 4 OP connection mode is defined by the rightmost
- *	bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves.
- *
- *	First half	Second half	Mode
+ *	opl3.h
  *
- *					 +---+
- *					 v   |
- *	0		0		>+-1-+--2--3--4-->
+ * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
  *
- *
- *					
- *					 +---+
- *					 |   |
- *	0		1		>+-1-+--2-+
- *						  |->
- *					>--3----4-+
- *					
- *					 +---+
- *					 |   |
- *	1		0		>+-1-+-----+
- *						   |->
- *					>--2--3--4-+
- *
- *					 +---+
- *					 |   |
- *	1		1		>+-1-+--+
- *						|
- *					>--2--3-+->
- *						|
- *					>--4----+
- */
-#define   STEREO_BITS				0x30	/* OPL-3 only */
-#define     VOICE_TO_LEFT		0x10
-#define     VOICE_TO_RIGHT		0x20
-
-/*
- * 	Definition table for the physical voices
  */
 
-struct physical_voice_info {
-		unsigned char voice_num;
-		unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
-		unsigned short ioaddr; /* I/O port (left or right side) */
-		unsigned char op[4]; /* Operator offsets */
-	};
-
-/*
- *	There is 18 possible 2 OP voices
- *	(9 in the left and 9 in the right).
- *	The first OP is the modulator and 2nd is the carrier.
- *
- *	The first three voices in the both sides may be connected
- *	with another voice to a 4 OP voice. For example voice 0
- *	can be connected with voice 3. The operators of voice 3 are
- *	used as operators 3 and 4 of the new 4 OP voice.
- *	In this case the 2 OP voice number 0 is the 'first half' and
- *	voice 3 is the second.
- */
-
-#define USE_LEFT	0
-#define USE_RIGHT	1
-
-static struct physical_voice_info pv_map[18] =
-{
-/*       No Mode Side		OP1	OP2	OP3   OP4	*/
-/*	---------------------------------------------------	*/
-	{ 0,  2, USE_LEFT,	{0x00,	0x03,	0x08, 0x0b}},
-	{ 1,  2, USE_LEFT,	{0x01,	0x04,	0x09, 0x0c}},
-	{ 2,  2, USE_LEFT,	{0x02,	0x05,	0x0a, 0x0d}},
-
-	{ 3,  2, USE_LEFT,	{0x08,	0x0b,	0x00, 0x00}},
-	{ 4,  2, USE_LEFT,	{0x09,	0x0c,	0x00, 0x00}},
-	{ 5,  2, USE_LEFT,	{0x0a,	0x0d,	0x00, 0x00}},
-
-	{ 6,  2, USE_LEFT,	{0x10,	0x13,	0x00, 0x00}}, /* Used by percussive voices */
-	{ 7,  2, USE_LEFT,	{0x11,	0x14,	0x00, 0x00}}, /* if the percussive mode */
-	{ 8,  2, USE_LEFT,	{0x12,	0x15,	0x00, 0x00}}, /* is selected */
-
-	{ 0,  2, USE_RIGHT,	{0x00,	0x03,	0x08, 0x0b}},
-	{ 1,  2, USE_RIGHT,	{0x01,	0x04,	0x09, 0x0c}},
-	{ 2,  2, USE_RIGHT,	{0x02,	0x05,	0x0a, 0x0d}},
-
-	{ 3,  2, USE_RIGHT,	{0x08,	0x0b,	0x00, 0x00}},
-	{ 4,  2, USE_RIGHT,	{0x09,	0x0c,	0x00, 0x00}},
-	{ 5,  2, USE_RIGHT,	{0x0a,	0x0d,	0x00, 0x00}},
+int opl3_detect (int ioaddr, int *osp);
+int opl3_init(int ioaddr, int *osp);
 
-	{ 6,  2, USE_RIGHT,	{0x10,	0x13,	0x00, 0x00}},
-	{ 7,  2, USE_RIGHT,	{0x11,	0x14,	0x00, 0x00}},
-	{ 8,  2, USE_RIGHT,	{0x12,	0x15,	0x00, 0x00}}
-};
+void enable_opl3_mode(int left, int right, int both);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3_hw.h linux/drivers/sound/opl3_hw.h
--- v2.3.49/linux/drivers/sound/opl3_hw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/opl3_hw.h	Tue Mar  7 13:40:24 2000
@@ -0,0 +1,246 @@
+/*
+ *	opl3_hw.h	- Definitions of the OPL-3 registers
+ *
+ *
+ * Copyright (C) by Hannu Savolainen 1993-1997
+ *
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ *
+ *
+ *	The OPL-3 mode is switched on by writing 0x01, to the offset 5
+ *	of the right side.
+ *
+ *	Another special register at the right side is at offset 4. It contains
+ *	a bit mask defining which voices are used as 4 OP voices.
+ *
+ *	The percussive mode is implemented in the left side only.
+ *
+ *	With the above exceptions the both sides can be operated independently.
+ *	
+ *	A 4 OP voice can be created by setting the corresponding
+ *	bit at offset 4 of the right side.
+ *
+ *	For example setting the rightmost bit (0x01) changes the
+ *	first voice on the right side to the 4 OP mode. The fourth
+ *	voice is made inaccessible.
+ *
+ *	If a voice is set to the 2 OP mode, it works like 2 OP modes
+ *	of the original YM3812 (AdLib). In addition the voice can 
+ *	be connected the left, right or both stereo channels. It can
+ *	even be left unconnected. This works with 4 OP voices also.
+ *
+ *	The stereo connection bits are located in the FEEDBACK_CONNECTION
+ *	register of the voice (0xC0-0xC8). In 4 OP voices these bits are
+ *	in the second half of the voice.
+ */
+
+/*
+ *	Register numbers for the global registers
+ */
+
+#define TEST_REGISTER				0x01
+#define   ENABLE_WAVE_SELECT		0x20
+
+#define TIMER1_REGISTER				0x02
+#define TIMER2_REGISTER				0x03
+#define TIMER_CONTROL_REGISTER			0x04	/* Left side */
+#define   IRQ_RESET			0x80
+#define   TIMER1_MASK			0x40
+#define   TIMER2_MASK			0x20
+#define   TIMER1_START			0x01
+#define   TIMER2_START			0x02
+
+#define CONNECTION_SELECT_REGISTER		0x04	/* Right side */
+#define   RIGHT_4OP_0			0x01
+#define   RIGHT_4OP_1			0x02
+#define   RIGHT_4OP_2			0x04
+#define   LEFT_4OP_0			0x08
+#define   LEFT_4OP_1			0x10
+#define   LEFT_4OP_2			0x20
+
+#define OPL3_MODE_REGISTER			0x05	/* Right side */
+#define   OPL3_ENABLE			0x01
+#define   OPL4_ENABLE			0x02
+
+#define KBD_SPLIT_REGISTER			0x08	/* Left side */
+#define   COMPOSITE_SINE_WAVE_MODE	0x80		/* Don't use with OPL-3? */
+#define   KEYBOARD_SPLIT		0x40
+
+#define PERCOSSION_REGISTER			0xbd	/* Left side only */
+#define   TREMOLO_DEPTH			0x80
+#define   VIBRATO_DEPTH			0x40
+#define	  PERCOSSION_ENABLE		0x20
+#define   BASSDRUM_ON			0x10
+#define   SNAREDRUM_ON			0x08
+#define   TOMTOM_ON			0x04
+#define   CYMBAL_ON			0x02
+#define   HIHAT_ON			0x01
+
+/*
+ *	Offsets to the register banks for operators. To get the
+ *	register number just add the operator offset to the bank offset
+ *
+ *	AM/VIB/EG/KSR/Multiple (0x20 to 0x35)
+ */
+#define AM_VIB					0x20
+#define   TREMOLO_ON			0x80
+#define   VIBRATO_ON			0x40
+#define   SUSTAIN_ON			0x20
+#define   KSR				0x10 	/* Key scaling rate */
+#define   MULTIPLE_MASK		0x0f	/* Frequency multiplier */
+
+ /*
+  *	KSL/Total level (0x40 to 0x55)
+  */
+#define KSL_LEVEL				0x40
+#define   KSL_MASK			0xc0	/* Envelope scaling bits */
+#define   TOTAL_LEVEL_MASK		0x3f	/* Strength (volume) of OP */
+
+/*
+ *	Attack / Decay rate (0x60 to 0x75)
+ */
+#define ATTACK_DECAY				0x60
+#define   ATTACK_MASK			0xf0
+#define   DECAY_MASK			0x0f
+
+/*
+ * Sustain level / Release rate (0x80 to 0x95)
+ */
+#define SUSTAIN_RELEASE				0x80
+#define   SUSTAIN_MASK			0xf0
+#define   RELEASE_MASK			0x0f
+
+/*
+ * Wave select (0xE0 to 0xF5)
+ */
+#define WAVE_SELECT			0xe0
+
+/*
+ *	Offsets to the register banks for voices. Just add to the
+ *	voice number to get the register number.
+ *
+ *	F-Number low bits (0xA0 to 0xA8).
+ */
+#define FNUM_LOW				0xa0
+
+/*
+ *	F-number high bits / Key on / Block (octave) (0xB0 to 0xB8)
+ */
+#define KEYON_BLOCK					0xb0
+#define	  KEYON_BIT				0x20
+#define	  BLOCKNUM_MASK				0x1c
+#define   FNUM_HIGH_MASK			0x03
+
+/*
+ *	Feedback / Connection (0xc0 to 0xc8)
+ *
+ *	These registers have two new bits when the OPL-3 mode
+ *	is selected. These bits controls connecting the voice
+ *	to the stereo channels. For 4 OP voices this bit is
+ *	defined in the second half of the voice (add 3 to the
+ *	register offset).
+ *
+ *	For 4 OP voices the connection bit is used in the
+ *	both halves (gives 4 ways to connect the operators).
+ */
+#define FEEDBACK_CONNECTION				0xc0
+#define   FEEDBACK_MASK				0x0e	/* Valid just for 1st OP of a voice */
+#define   CONNECTION_BIT			0x01
+/*
+ *	In the 4 OP mode there is four possible configurations how the
+ *	operators can be connected together (in 2 OP modes there is just
+ *	AM or FM). The 4 OP connection mode is defined by the rightmost
+ *	bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves.
+ *
+ *	First half	Second half	Mode
+ *
+ *					 +---+
+ *					 v   |
+ *	0		0		>+-1-+--2--3--4-->
+ *
+ *
+ *					
+ *					 +---+
+ *					 |   |
+ *	0		1		>+-1-+--2-+
+ *						  |->
+ *					>--3----4-+
+ *					
+ *					 +---+
+ *					 |   |
+ *	1		0		>+-1-+-----+
+ *						   |->
+ *					>--2--3--4-+
+ *
+ *					 +---+
+ *					 |   |
+ *	1		1		>+-1-+--+
+ *						|
+ *					>--2--3-+->
+ *						|
+ *					>--4----+
+ */
+#define   STEREO_BITS				0x30	/* OPL-3 only */
+#define     VOICE_TO_LEFT		0x10
+#define     VOICE_TO_RIGHT		0x20
+
+/*
+ * 	Definition table for the physical voices
+ */
+
+struct physical_voice_info {
+		unsigned char voice_num;
+		unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
+		unsigned short ioaddr; /* I/O port (left or right side) */
+		unsigned char op[4]; /* Operator offsets */
+	};
+
+/*
+ *	There is 18 possible 2 OP voices
+ *	(9 in the left and 9 in the right).
+ *	The first OP is the modulator and 2nd is the carrier.
+ *
+ *	The first three voices in the both sides may be connected
+ *	with another voice to a 4 OP voice. For example voice 0
+ *	can be connected with voice 3. The operators of voice 3 are
+ *	used as operators 3 and 4 of the new 4 OP voice.
+ *	In this case the 2 OP voice number 0 is the 'first half' and
+ *	voice 3 is the second.
+ */
+
+#define USE_LEFT	0
+#define USE_RIGHT	1
+
+static struct physical_voice_info pv_map[18] =
+{
+/*       No Mode Side		OP1	OP2	OP3   OP4	*/
+/*	---------------------------------------------------	*/
+	{ 0,  2, USE_LEFT,	{0x00,	0x03,	0x08, 0x0b}},
+	{ 1,  2, USE_LEFT,	{0x01,	0x04,	0x09, 0x0c}},
+	{ 2,  2, USE_LEFT,	{0x02,	0x05,	0x0a, 0x0d}},
+
+	{ 3,  2, USE_LEFT,	{0x08,	0x0b,	0x00, 0x00}},
+	{ 4,  2, USE_LEFT,	{0x09,	0x0c,	0x00, 0x00}},
+	{ 5,  2, USE_LEFT,	{0x0a,	0x0d,	0x00, 0x00}},
+
+	{ 6,  2, USE_LEFT,	{0x10,	0x13,	0x00, 0x00}}, /* Used by percussive voices */
+	{ 7,  2, USE_LEFT,	{0x11,	0x14,	0x00, 0x00}}, /* if the percussive mode */
+	{ 8,  2, USE_LEFT,	{0x12,	0x15,	0x00, 0x00}}, /* is selected */
+
+	{ 0,  2, USE_RIGHT,	{0x00,	0x03,	0x08, 0x0b}},
+	{ 1,  2, USE_RIGHT,	{0x01,	0x04,	0x09, 0x0c}},
+	{ 2,  2, USE_RIGHT,	{0x02,	0x05,	0x0a, 0x0d}},
+
+	{ 3,  2, USE_RIGHT,	{0x08,	0x0b,	0x00, 0x00}},
+	{ 4,  2, USE_RIGHT,	{0x09,	0x0c,	0x00, 0x00}},
+	{ 5,  2, USE_RIGHT,	{0x0a,	0x0d,	0x00, 0x00}},
+
+	{ 6,  2, USE_RIGHT,	{0x10,	0x13,	0x00, 0x00}},
+	{ 7,  2, USE_RIGHT,	{0x11,	0x14,	0x00, 0x00}},
+	{ 8,  2, USE_RIGHT,	{0x12,	0x15,	0x00, 0x00}}
+};
+/*
+ *	DMA buffer calls
+ */
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c
--- v2.3.49/linux/drivers/sound/opl3sa.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/opl3sa.c	Tue Mar  7 13:40:24 2000
@@ -13,21 +13,26 @@
  *
  * Changes:
  *	Alan Cox		Modularisation
+ *	Christoph Hellwig	Adapted to module_init/module_exit
  *
  * FIXME:
  * 	Check for install of mpu etc is wrong, should check result of the mss stuff
  */
- 
+
+#include <linux/init.h>
 #include <linux/module.h>
 
 #undef  SB_OK
 
 #include "sound_config.h"
 #include "soundmodule.h"
+
+#include "ad1848.h"
+#include "mpu401.h"
+
 #ifdef SB_OK
 #include "sb.h"
 static int sb_initialized = 0;
-
 #endif
 
 static int kilroy_was_here = 0;	/* Don't detect twice */
@@ -62,7 +67,7 @@
 	restore_flags(flags);
 }
 
-static int opl3sa_detect(void)
+static int __init opl3sa_detect(void)
 {
 	int tmp;
 
@@ -102,7 +107,7 @@
  *     OPL3-SA
  */
 
-int probe_opl3sa_wss(struct address_info *hw_config)
+static int __init probe_opl3sa_wss(struct address_info *hw_config)
 {
 	int ret;
 	unsigned char tmp = 0x24;	/* WSS enable */
@@ -157,7 +162,7 @@
 	return ret;
 }
 
-void attach_opl3sa_wss(struct address_info *hw_config)
+static void __init attach_opl3sa_wss(struct address_info *hw_config)
 {
 	int nm = num_mixers;
 
@@ -172,13 +177,13 @@
 }
 
 
-void attach_opl3sa_mpu(struct address_info *hw_config)
+static void __init attach_opl3sa_mpu(struct address_info *hw_config)
 {
 	hw_config->name = "OPL3-SA (MPU401)";
 	attach_uart401(hw_config);
 }
 
-int probe_opl3sa_mpu(struct address_info *hw_config)
+static int __init probe_opl3sa_mpu(struct address_info *hw_config)
 {
 	unsigned char conf;
 	static signed char irq_bits[] = {
@@ -236,7 +241,7 @@
 	return probe_uart401(hw_config);
 }
 
-void unload_opl3sa_wss(struct address_info *hw_config)
+static void __exit unload_opl3sa_wss(struct address_info *hw_config)
 {
 	int dma2 = hw_config->dma2;
 
@@ -254,26 +259,29 @@
 	sound_unload_audiodev(hw_config->slots[0]);
 }
 
-void unload_opl3sa_mpu(struct address_info *hw_config)
+static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
 {
 	unload_uart401(hw_config);
 }
 
 #ifdef SB_OK
-void unload_opl3sa_sb(struct address_info *hw_config)
+static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
 {
 	sb_dsp_unload(hw_config);
 }
 #endif
 
-#ifdef MODULE
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma2 = -1;
+static int found_mpu;
+
+static struct address_info cfg;
+static struct address_info cfg_mpu;
 
-int		mpu_io = -1;
-int 		mpu_irq = -1;
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma2	= -1;
+static int __initdata mpu_io	= -1;
+static int __initdata mpu_irq	= -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
@@ -282,43 +290,61 @@
 MODULE_PARM(mpu_io,"i");
 MODULE_PARM(mpu_irq,"i");
 
-struct address_info cfg;
-struct address_info mpu_cfg;
-static int found_mpu;
-
-int init_module(void)
+static int __init init_opl3sa(void)
 {
-	if (io == -1 || irq == -1 || dma == -1)
-	{
+	if (io == -1 || irq == -1 || dma == -1) {
 		printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
 		return -EINVAL;
 	}
+
 	cfg.io_base = io;
 	cfg.irq = irq;
 	cfg.dma = dma;
 	cfg.dma2 = dma2;
 	
-	mpu_cfg.io_base = mpu_io;
-	mpu_cfg.irq = mpu_irq;
+	cfg_mpu.io_base = mpu_io;
+	cfg_mpu.irq = mpu_irq;
 
 	if (probe_opl3sa_wss(&cfg) == 0)
 		return -ENODEV;
 
-	found_mpu=probe_opl3sa_mpu(&mpu_cfg);
+	found_mpu=probe_opl3sa_mpu(&cfg_mpu);
 
 	attach_opl3sa_wss(&cfg);
 	if(found_mpu)
-		attach_opl3sa_mpu(&mpu_cfg);
+		attach_opl3sa_mpu(&cfg_mpu);
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_opl3sa(void)
 {
 	if(found_mpu)
-		unload_opl3sa_mpu(&mpu_cfg);
+		unload_opl3sa_mpu(&cfg_mpu);
 	unload_opl3sa_wss(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_opl3sa);
+module_exit(cleanup_opl3sa);
+
+#ifndef MODULE
+static int __init setup_opl3sa(char *str)
+{
+	/* io, irq, dma, dma2, mpu_io, mpu_irq */
+	int ints[7];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma2	= ints[4];
+	mpu_io	= ints[5];
+	mpu_irq	= ints[6];
+
+	return 1;
+}
+
+__setup("opl3sa=", setup_opl3sa);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c
--- v2.3.49/linux/drivers/sound/opl3sa2.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/opl3sa2.c	Tue Mar  7 13:40:24 2000
@@ -32,15 +32,20 @@
  * Scott Murray            Simpler detection code should work all the time now
  *                         (with thanks to Ben Hutchings for the heuristic),
  *                         removed now unnecessary force option. (Jan 5, 1999)
+ * Christoph Hellwig	   Adapted to module_init/module_exit (Mar 4, 2000)
  *
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 
+#include "ad1848.h"
+#include "mpu401.h"
+
 /* Useful control port indexes: */
 #define OPL3SA2_MASTER_LEFT  0x07
 #define OPL3SA2_MASTER_RIGHT 0x08
@@ -439,31 +444,31 @@
 /* End of mixer-related stuff */
 
 
-int probe_opl3sa2_mpu(struct address_info *hw_config)
+static inline int __init probe_opl3sa2_mpu(struct address_info *hw_config)
 {
 	return probe_mpu401(hw_config);
 }
 
 
-void attach_opl3sa2_mpu(struct address_info *hw_config)
+static inline void __init attach_opl3sa2_mpu(struct address_info *hw_config)
 {
 	attach_mpu401(hw_config);
 }
 
 
-void unload_opl3sa2_mpu(struct address_info *hw_config)
+static inline void __exit unload_opl3sa2_mpu(struct address_info *hw_config)
 {
 	unload_mpu401(hw_config);
 }
 
 
-int probe_opl3sa2_mss(struct address_info *hw_config)
+static inline int __init probe_opl3sa2_mss(struct address_info *hw_config)
 {
 	return probe_ms_sound(hw_config);
 }
 
 
-void attach_opl3sa2_mss(struct address_info *hw_config)
+static void __init attach_opl3sa2_mss(struct address_info *hw_config)
 {
 	char mixer_name[64];
 
@@ -506,13 +511,13 @@
 }
 
 
-void unload_opl3sa2_mss(struct address_info *hw_config)
+static inline void __exit unload_opl3sa2_mss(struct address_info *hw_config)
 {
 	unload_ms_sound(hw_config);
 }
 
 
-int probe_opl3sa2(struct address_info *hw_config)
+static int __init probe_opl3sa2(struct address_info *hw_config)
 {
 	unsigned char version = 0;
 	char tag;
@@ -582,16 +587,13 @@
 	{
 		/* 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;
 }
 
 
-void attach_opl3sa2(struct address_info *hw_config)
+static void __init attach_opl3sa2(struct address_info *hw_config)
 {
    	request_region(hw_config->io_base, 2, chipset_name);
 
@@ -599,7 +601,7 @@
 }
 
 
-void unload_opl3sa2(struct address_info *hw_config)
+static void __exit unload_opl3sa2(struct address_info *hw_config)
 {
         /* Release control ports */
 	release_region(hw_config->io_base, 2);
@@ -609,15 +611,16 @@
 		sound_unload_mixerdev(opl3sa2_mixer);
 }
 
-
-#ifdef MODULE
-
-int io      = -1;
-int mss_io  = -1;
-int mpu_io  = -1;
-int irq     = -1;
-int dma     = -1;
-int dma2    = -1;
+static struct address_info cfg;
+static struct address_info cfg2;
+static struct address_info cfg_mpu;
+
+static int __initdata io	= -1;
+static int __initdata mss_io	= -1;
+static int __initdata mpu_io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma2	= -1;
 
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "Set i/o base of OPL3-SA2 or SA3 card (usually 0x370)");
@@ -640,30 +643,15 @@
 MODULE_DESCRIPTION("Module for OPL3-SA2 and SA3 sound cards (uses AD1848 MSS driver).");
 MODULE_AUTHOR("Scott Murray <scottm@interlog.com>");
 
-EXPORT_NO_SYMBOLS;
-
-struct address_info cfg;
-struct address_info mss_cfg;
-struct address_info mpu_cfg;
-
-
 /*
  * Install a OPL3SA2 based card.
  *
  * Need to have ad1848 and mpu401 loaded ready.
  */
-int init_module(void)
+static int __init init_opl3sa2(void)
 {
         int i;
 
-	if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1)
-	{
-		printk(KERN_ERR
-		       "%s: io, mss_io, irq, dma, and dma2 must be set.\n",
-		       __FILE__);
-		return -EINVAL;
-	}
-   
         /* Our own config: */
         cfg.io_base = io;
 	cfg.irq     = irq;
@@ -671,16 +659,26 @@
 	cfg.dma2    = dma2;
 	
         /* The MSS config: */
-	mss_cfg.io_base      = mss_io;
-	mss_cfg.irq          = irq;
-	mss_cfg.dma          = dma;
-	mss_cfg.dma2         = dma2;
-	mss_cfg.card_subtype = 1;      /* No IRQ or DMA setup */
+	cfg2.io_base      = mss_io;
+	cfg2.irq          = irq;
+	cfg2.dma          = dma;
+	cfg2.dma2         = dma2;
+	cfg2.card_subtype = 1;      /* No IRQ or DMA setup */
+
+	cfg_mpu.io_base       = mpu_io;
+	cfg_mpu.irq           = irq;
+	cfg_mpu.dma           = dma;
+	cfg_mpu.always_detect = 1;  /* It's there, so use shared IRQs */
+
+	if(cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.dma2 == -1 || cfg2.io_base == -1) {
+		printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set.\n");
+		return -EINVAL;
+	}
 
 	/* Call me paranoid: */
 	for(i = 0; i < 6; i++)
 	{
-		cfg.slots[i] = mss_cfg.slots[i] = mpu_cfg.slots[i] = -1;
+		cfg.slots[i] = cfg2.slots[i] = cfg_mpu.slots[i] = -1;
 	}
 
 	if(probe_opl3sa2(&cfg) == 0)
@@ -688,41 +686,54 @@
 		return -ENODEV;
 	}
 
-	if(probe_opl3sa2_mss(&mss_cfg) == 0)
+	if(probe_opl3sa2_mss(&cfg2) == 0)
 	{
 		return -ENODEV;
 	}
 
 	attach_opl3sa2(&cfg);
-	attach_opl3sa2_mss(&mss_cfg);
+	attach_opl3sa2_mss(&cfg2);
 
-	if(mpu_io != -1)
-	{
-            /* MPU config: */
-	    mpu_cfg.io_base       = mpu_io;
-	    mpu_cfg.irq           = irq;
-	    mpu_cfg.dma           = dma;
-	    mpu_cfg.always_detect = 1;  /* It's there, so use shared IRQs */
-
-	    if(probe_opl3sa2_mpu(&mpu_cfg))
-	    {
-		    attach_opl3sa2_mpu(&mpu_cfg);
-	    }
+	if(cfg_mpu.io_base != -1) {
+		if(probe_opl3sa2_mpu(&cfg_mpu)) {
+			attach_opl3sa2_mpu(&cfg_mpu);
+		}
 	}
 	SOUND_LOCK;
 	return 0;
 }
 
 
-void cleanup_module(void)
+static void __exit cleanup_opl3sa2(void)
 {
-        if(mpu_cfg.slots[1] != -1)
-	{
-		unload_opl3sa2_mpu(&mpu_cfg);
+        if(cfg_mpu.slots[1] != -1) {
+		unload_opl3sa2_mpu(&cfg_mpu);
 	}
-	unload_opl3sa2_mss(&mss_cfg);
+	unload_opl3sa2_mss(&cfg2);
 	unload_opl3sa2(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_opl3sa2);
+module_exit(cleanup_opl3sa2);
+
+#ifndef MODULE
+static int __init setup_opl3sa2(char *str)
+{
+	/* io, irq, dma, dma2 */
+	int ints[7];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma2	= ints[4];
+	mss_io	= ints[5];
+	mpu_io	= ints[6];
+
+	return 1;
+}
+
+__setup("opl3sa2=", setup_opl3sa2);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2.h linux/drivers/sound/pas2.h
--- v2.3.49/linux/drivers/sound/pas2.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/pas2.h	Tue Mar  7 13:40:24 2000
@@ -0,0 +1,23 @@
+/*
+ * pas2.h
+ *
+ * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
+ *
+ */
+
+/*	From pas_card.c	*/
+int pas_set_intr(int mask);
+int pas_remove_intr(int mask);
+unsigned char pas_read(int ioaddr);
+void pas_write(unsigned char data, int ioaddr);
+
+/*	From pas_audio.c */
+void pas_pcm_interrupt(unsigned char status, int cause);
+void pas_pcm_init(struct address_info *hw_config);
+
+/*	From pas_mixer.c */
+int pas_init_mixer(void);
+
+/*	From pas_midi.c */
+void pas_midi_init(void);
+void pas_midi_interrupt(void);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v2.3.49/linux/drivers/sound/pas2_card.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/pas2_card.c	Tue Mar  7 13:40:24 2000
@@ -5,10 +5,14 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 #include "sound_config.h"
 #include "soundmodule.h"
 
+#include "pas2.h"
+#include "sb.h"
+
 static unsigned char dma_bits[] = {
 	4, 1, 2, 3, 0, 5, 6, 7
 };
@@ -51,6 +55,8 @@
 static int	broken_bus_clock = 0;
 #endif
 
+static struct address_info cfg;
+static struct address_info cfg2;
 
 char            pas_model = 0;
 static char    *pas_model_names[] = {
@@ -81,7 +87,7 @@
 
 /******************* Begin of the Interrupt Handler ********************/
 
-static void pasintr(int irq, void *dev_id, struct pt_regs *dummy)
+void pasintr(int irq, void *dev_id, struct pt_regs *dummy)
 {
 	int             status;
 
@@ -126,9 +132,7 @@
 
 /******************* Begin of the Initialization Code ******************/
 
-extern struct address_info sbhw_config;
-
-static int config_pas_hw(struct address_info *hw_config)
+static int __init config_pas_hw(struct address_info *hw_config)
 {
 	char            ok = 1;
 	unsigned        int_ptrs;	/* scsi/sound interrupt pointers */
@@ -238,12 +242,8 @@
 	{
 		struct address_info *sb_config;
 
-#ifndef MODULE
-		if ((sb_config = sound_getconf(SNDCARD_SB)))
-#else
-		sb_config = &sbhw_config;
+		sb_config = &cfg2;
 		if (sb_config->io_base)
-#endif
 		{
 			unsigned char   irq_dma;
 
@@ -286,7 +286,7 @@
 	return ok;
 }
 
-static int detect_pas_hw(struct address_info *hw_config)
+static int __init detect_pas_hw(struct address_info *hw_config)
 {
 	unsigned char   board_id, foo;
 
@@ -327,7 +327,7 @@
 	return pas_model;
 }
 
-void attach_pas_card(struct address_info *hw_config)
+static void __init attach_pas_card(struct address_info *hw_config)
 {
 	pas_irq = hw_config->irq;
 
@@ -348,7 +348,6 @@
 			pas_pcm_init(hw_config);
 
 #if !defined(MODULE) && !defined(DISABLE_SB_EMULATION)
-
 			sb_dsp_disable_midi(pas_sb_base);	/* No MIDI capability */
 #endif
 
@@ -358,12 +357,12 @@
 	}
 }
 
-int probe_pas(struct address_info *hw_config)
+static inline int __init probe_pas(struct address_info *hw_config)
 {
 	return detect_pas_hw(hw_config);
 }
 
-void unload_pas(struct address_info *hw_config)
+static void __exit unload_pas(struct address_info *hw_config)
 {
 	extern int pas_audiodev;
 	extern int pas2_mididev;
@@ -381,17 +380,15 @@
 		sound_unload_audiodev(pas_audiodev);
 }
 
-#ifdef MODULE
-
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma16 = -1;	/* Set this for modules that need it */
-
-int             sb_io = 0;
-int             sb_irq = -1;
-int             sb_dma = -1;
-int             sb_dma16 = -1;
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma16	= -1;	/* Set this for modules that need it */
+
+static int __initdata sb_io	= 0;
+static int __initdata sb_irq	= -1;
+static int __initdata sb_dma	= -1;
+static int __initdata sb_dma16	= -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
@@ -407,40 +404,61 @@
 MODULE_PARM(symphony,"i");
 MODULE_PARM(broken_bus_clock,"i");
 
-struct address_info config;
-struct address_info sbhw_config;
-
-int init_module(void)
+static int __init init_pas2(void)
 {
 	printk(KERN_INFO "Pro Audio Spectrum driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
-	if (io == -1 || dma == -1 || irq == -1)
-	{
-		  printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n");
-		  return -EINVAL;
+	cfg.io_base = io;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.dma2 = dma16;
+
+	cfg2.io_base = sb_io;
+	cfg2.irq = sb_irq;
+	cfg2.dma = sb_dma;
+	cfg2.dma2 = sb_dma16;
+
+	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
+		printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n");
+		return -EINVAL;
 	}
-	config.io_base = io;
-	config.irq = irq;
-	config.dma = dma;
-	config.dma2 = dma16;
-
-	sbhw_config.io_base = sb_io;
-	sbhw_config.irq = sb_irq;
-	sbhw_config.dma = sb_dma;
-	sbhw_config.dma2 = sb_dma16;
 
-	if (!probe_pas(&config))
+	if (!probe_pas(&cfg))
 		return -ENODEV;
-	attach_pas_card(&config);
+	attach_pas_card(&cfg);
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_pas2(void)
 {
-	unload_pas(&config);
+	unload_pas(&cfg);
 	SOUND_LOCK_END;
 }
 
+module_init(init_pas2);
+module_exit(cleanup_pas2);
 
-#endif /* MODULE */
+#ifndef MODULE
+static int __init setup_pas2(char *str)
+{
+	/* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, sb_dma2 */
+	int ints[9];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma16	= ints[4];
+
+	sb_io	= ints[5];
+	sb_irq	= ints[6];
+	sb_dma	= ints[7];
+	sb_dma16 = ints[8];
+
+	return 1;
+}
+
+__setup("pas2=", setup_pas2);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c
--- v2.3.49/linux/drivers/sound/pas2_midi.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/pas2_midi.c	Tue Mar  7 13:40:24 2000
@@ -10,7 +10,10 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+
 #include "sound_config.h"
+
+#include "pas2.h"
 
 static int      midi_busy = 0, input_opened = 0;
 static int      my_dev;
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v2.3.49/linux/drivers/sound/pas2_mixer.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/pas2_mixer.c	Tue Mar  7 13:40:24 2000
@@ -17,6 +17,8 @@
  */
 #include "sound_config.h"
 
+#include "pas2.h"
+
 #ifndef DEB
 #define DEB(what)		/* (what) */
 #endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v2.3.49/linux/drivers/sound/pas2_pcm.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/pas2_pcm.c	Tue Mar  7 13:40:24 2000
@@ -16,6 +16,8 @@
 
 #include "sound_config.h"
 
+#include "pas2.h"
+
 #ifndef DEB
 #define DEB(WHAT)
 #endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v2.3.49/linux/drivers/sound/pss.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/pss.c	Tue Mar  7 13:40:24 2000
@@ -24,16 +24,22 @@
  *          To probe_pss_mss added test for initialize AD1848
  * 98-05-28: Vladimir Michl <vladimir.michl@upol.cz>
  *          Fixed computation of mixer volumes
+ * 00-03-03: Christoph Hellwig <chhellwig@gmx.net>
+ *          Adapted to module_init/module_exit
  */
 
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
 #include "sound_firmware.h"
 #include "soundmodule.h"
 
+#include "ad1848.h"
+#include "mpu401.h"
+
 /*
  * PSS registers.
  */
@@ -910,14 +916,14 @@
 	&pss_data
 };
 
-void attach_pss_mpu(struct address_info *hw_config)
+static void __init attach_pss_mpu(struct address_info *hw_config)
 {
 	attach_mpu401(hw_config);	/* Slot 1 */
 	if (hw_config->slots[1] != -1)	/* The MPU driver installed itself */
 		midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations;
 }
 
-int probe_pss_mss(struct address_info *hw_config)
+static int __init probe_pss_mss(struct address_info *hw_config)
 {
 	volatile int timeout;
 
@@ -950,16 +956,20 @@
 	 * downloaded to the ADSP2115 spends some time initializing the card.
 	 * Let's try to wait until it finishes this task.
 	 */
-	for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) & WSS_INITIALIZING); timeout++);
+	for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) &
+	  WSS_INITIALIZING); timeout++)
+		;
 
 	outb((0x0b), hw_config->io_base + WSS_INDEX);	/* Required by some cards */
 
-	for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && (timeout < 100000); timeout++);
+	for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) &&
+	  (timeout < 100000); timeout++)
+		;
 
 	return probe_ms_sound(hw_config);
 }
 
-void attach_pss_mss(struct address_info *hw_config)
+static void __init attach_pss_mss(struct address_info *hw_config)
 {
 	int        my_mix = -999;	/* gcc shut up */
 	
@@ -991,36 +1001,33 @@
 	}
 }
 
-void unload_pss(struct address_info *hw_config)
+static inline void __exit unload_pss(struct address_info *hw_config)
 {
 	release_region(hw_config->io_base, 0x10);
 	release_region(hw_config->io_base+0x10, 0x9);
 }
 
-void unload_pss_mpu(struct address_info *hw_config)
+static inline void __exit unload_pss_mpu(struct address_info *hw_config)
 {
 	unload_mpu401(hw_config);
 }
 
-void unload_pss_mss(struct address_info *hw_config)
+static inline void __exit unload_pss_mss(struct address_info *hw_config)
 {
 	unload_ms_sound(hw_config);
 }
 
-#ifdef MODULE
-
-int pss_io = -1;
-
-int mss_io = -1;
-int mss_irq = -1;
-int mss_dma = -1;
 
-int mpu_io = -1;
-int mpu_irq = -1;
-
-struct address_info cfgpss = { 0 /* pss_io */, 0, -1, -1 };
-struct address_info cfgmpu = { 0 /* mpu_io */, 0 /* mpu_irq */, 0, -1 };
-struct address_info cfgmss = { 0 /* mss_io */, 0 /* mss_irq */, 0 /* mss_dma */, -1 };
+static struct address_info cfg;
+static struct address_info cfg2;
+static struct address_info cfg_mpu;
+
+static int pss_io __initdata	= -1;
+static int mss_io __initdata	= -1;
+static int mss_irq __initdata	= -1;
+static int mss_dma __initdata	= -1;
+static int mpu_io __initdata	= -1;
+static int mpu_irq __initdata	= -1;
 
 MODULE_PARM(pss_io, "i");
 MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)");
@@ -1046,54 +1053,76 @@
  *    Load a PSS sound card module
  */
 
-int init_module(void)
+static int __init init_pss(void)
 {
-	if (pss_io == -1 || mss_io == -1 || mss_irq == -1 || mss_dma == -1) {
-		printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n");
-		return -EINVAL;
-	}
+	cfg.io_base = pss_io;
 
-	cfgpss.io_base = pss_io;
+	cfg2.io_base = mss_io;
+	cfg2.irq = mss_irq;
+	cfg2.dma = mss_dma;
 
-	cfgmss.io_base = mss_io;
-	cfgmss.irq = mss_irq;
-	cfgmss.dma = mss_dma;
+	cfg_mpu.io_base = mpu_io;
+	cfg_mpu.irq = mpu_irq;
 
-	cfgmpu.io_base = mpu_io;
-	cfgmpu.irq = mpu_irq;
+	if (cfg.io_base == -1 || cfg2.io_base == -1 || cfg2.irq == -1 || cfg.dma == -1) {
+		printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n");
+		return -EINVAL;
+	}
 
-	if (!pss_synth) 
-	{
+	if (!pss_synth) {
 		fw_load = 1;
 		pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth);
 	}
-	if (!probe_pss(&cfgpss))
+	if (!probe_pss(&cfg))
 		return -ENODEV;
-	attach_pss(&cfgpss);
+	attach_pss(&cfg);
 	/*
 	 *    Attach stuff
 	 */
-	if (probe_pss_mpu(&cfgmpu)) {
+	if (probe_pss_mpu(&cfg_mpu)) {
 		pssmpu = 1;
-		attach_pss_mpu(&cfgmpu);
+		attach_pss_mpu(&cfg_mpu);
 	}
-	if (probe_pss_mss(&cfgmss)) {
+	if (probe_pss_mss(&cfg2)) {
 		pssmss = 1;
-		attach_pss_mss(&cfgmss);
+		attach_pss_mss(&cfg2);
 	}
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_pss(void)
 {
 	if (fw_load && pss_synth)
 		vfree(pss_synth);
 	if (pssmss)
-		unload_pss_mss(&cfgmss);
+		unload_pss_mss(&cfg2);
 	if (pssmpu)
-		unload_pss_mpu(&cfgmpu);
-	unload_pss(&cfgpss);
+		unload_pss_mpu(&cfg_mpu);
+	unload_pss(&cfg);
 	SOUND_LOCK_END;
 }
-#endif /* MODULE */
+
+module_init(init_pss);
+module_exit(cleanup_pss);
+
+#ifndef MODULE
+static int __init setup_pss(char *str)
+{
+	/* io, mss_io, mss_irq, mss_dma, mpu_io, mpu_irq */
+	int ints[7];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	pss_io	= ints[1];
+	mss_io	= ints[2];
+	mss_irq	= ints[3];
+	mss_dma	= ints[4];
+	mpu_io	= ints[5];
+	mpu_irq	= ints[6];
+
+	return 1;
+}
+
+__setup("pss=", setup_pss);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.3.49/linux/drivers/sound/sb.h	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/sb.h	Tue Mar  7 13:40:24 2000
@@ -164,3 +164,13 @@
 
 extern int acer;
 extern sb_devc *last_sb;
+
+/*	From sb_common.c */
+void sb_dsp_disable_midi(int port);
+void sb_dsp_disable_recording(int port);
+void attach_sbmpu (struct address_info *hw_config);
+int probe_sbmpu (struct address_info *hw_config);
+void unload_sbmpu (struct address_info *hw_config);
+
+void unload_sb16(struct address_info *hw_info);
+void unload_sb16midi(struct address_info *hw_info);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.3.49/linux/drivers/sound/sb_card.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/sb_card.c	Tue Mar  7 13:40:24 2000
@@ -11,19 +11,22 @@
  * for more info.
  *
  *
- * 26th November 1999 - patched to compile without ISA PnP support in the
- * kernel. -Daniel Stone (tamriel@ductape.net) 
+ * 26-11-1999 Patched to compile without ISA PnP support in the
+ * kernel - Daniel Stone (tamriel@ductape.net) 
  *
  * 06-01-2000 Refined and bugfixed ISA PnP support, added
  *  CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it>
  *
+ * 18-01-2000 Separated sb_card and sb_common
+ *  Jeff Garzik <jgarzik@mandrakesoft.com>
+ *
  * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump
  *  Alessandro Zummo <azummo@ita.flashnet.it>
  *
  * 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code
  *  Alessandro Zummo <azummo@ita.flashnet.it>
  *
- * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup.
+ * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup
  *  Alessandro Zummo <azummo@ita.flashnet.it>
  *
  */
@@ -42,14 +45,23 @@
 
 static int sbmpu = 0;
 
-void attach_sb_card(struct address_info *hw_config)
+extern void *smw_free;
+
+static void __init attach_sb_card(struct address_info *hw_config)
 {
 	if(!sb_dsp_init(hw_config))
 		hw_config->slots[0] = -1;
+	SOUND_LOCK;
 }
 
-int probe_sb(struct address_info *hw_config)
+static int __init probe_sb(struct address_info *hw_config)
 {
+	if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1)
+	{
+		printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
+		return -EINVAL;
+	}
+
 #ifdef CONFIG_MCA
 	/* MCA code added by ZP Gu (zpg@castle.net) */
 	if (MCA_bus) {               /* no multiple REPLY card probing */
@@ -121,19 +133,16 @@
 	return sb_dsp_detect(hw_config, 0, 0);
 }
 
-void unload_sb(struct address_info *hw_config)
+static void __exit unload_sb(struct address_info *hw_config)
 {
 	if(hw_config->slots[0]!=-1)
 		sb_dsp_unload(hw_config, sbmpu);
 }
 
-int sb_be_quiet=0;
 extern int esstype;	/* ESS chip type */
 
-#ifdef MODULE
-
-static struct address_info config;
-static struct address_info config_mpu;
+static struct address_info cfg;
+static struct address_info cfg_mpu;
 
 struct pci_dev 	*sb_dev 	= NULL, 
 		*wss_dev	= NULL, 
@@ -146,25 +155,21 @@
  *    to the 8bit channel.
  */
 
-int mpu_io 	= 0;
-int io 		= -1;
-int irq 	= -1;
-int dma 	= -1;
-int dma16 	= -1;	/* Set this for modules that need it */
-int type 	= 0;	/* Can set this to a specific card type */
-int mad16 	= 0;	/* Set mad16=1 to load this as support for mad16 */
-int trix 	= 0;	/* Set trix=1 to load this as support for trix */
-int pas2 	= 0;	/* Set pas2=1 to load this as support for pas2 */
-int support	= 0;	/* Set support to load this as a support module */
-int sm_games	= 0;	/* Mixer - see sb_mixer.c */
-int acer	= 0;	/* Do acer notebook init */
+static int __initdata mpu_io	= 0;
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma16	= -1;   /* Set this for modules that need it */
+static int __initdata type	= 0;    /* Can set this to a specific card type */
+
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-int isapnp      = 1;
-int isapnpjump  = 0;
-int nosbwave    = 0;	/* This option will be removed when the new awe_wave driver will be in the kernel tree */
+static int isapnp	= 1;
+static int isapnpjump	= 0;
+static int nosbwave	= 0;	/* This option will be removed when the new awe_wave driver will be
+				   in the kernel tree */
 #else
-int isapnp 	= 0;
+int isapnp	= 0;
 #endif
 
 MODULE_DESCRIPTION("Soundblaster driver");
@@ -175,10 +180,6 @@
 MODULE_PARM(dma16,	"i");
 MODULE_PARM(mpu_io,	"i");
 MODULE_PARM(type,	"i");
-MODULE_PARM(mad16,	"i");
-MODULE_PARM(support,	"i");
-MODULE_PARM(trix,	"i");
-MODULE_PARM(pas2,	"i");
 MODULE_PARM(sm_games,	"i");
 MODULE_PARM(esstype,	"i");
 MODULE_PARM(acer,	"i");
@@ -198,16 +199,10 @@
 MODULE_PARM_DESC(dma16,		"16-bit DMA channel (5,6,7)");
 MODULE_PARM_DESC(mpu_io,	"Mpu base address");
 MODULE_PARM_DESC(type,		"You can set this to specific card type");
-MODULE_PARM_DESC(mad16,		"Enable MAD16 support");
-MODULE_PARM_DESC(trix,		"Enable Audiotrix support");
-MODULE_PARM_DESC(pas2,		"Enable Pas2 support");
-MODULE_PARM_DESC(support,	"Set this to load as generic support module");
 MODULE_PARM_DESC(sm_games,	"Enable support for Logitech soundman games");
 MODULE_PARM_DESC(esstype,	"ESS chip type");
 MODULE_PARM_DESC(acer,		"Set this to detect cards in some ACER notebooks");
 
-void *smw_free = NULL;
-
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 
 /* That's useful. */
@@ -394,6 +389,97 @@
 	return(sb_dev);
 }
 
+static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
+{
+	/* 
+	 * Diamonds DT0197H
+	 * very similar to the CMI8330 above
+	 */
+
+	/*  @@@0001:Soundblaster.
+	 */
+
+	if((sb_dev = isapnp_find_dev(bus,
+				ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+	{
+		sb_dev->prepare(sb_dev);
+		
+		if((sb_dev = activate_dev("DT0197H", "sb", sb_dev)))
+		{
+			hw_config->io_base 	= sb_dev->resource[0].start;
+			hw_config->irq 		= sb_dev->irq_resource[0].start;
+			hw_config->dma 		= sb_dev->dma_resource[0].start;
+			hw_config->dma2 	= -1;
+
+			show_base("DT0197H", "sb", &sb_dev->resource[0]);
+		}
+
+		if(!sb_dev) return(NULL);
+
+	}
+	else
+		printk(KERN_ERR "sb: DT0197H panic: sb base not found\n");
+
+	/*  @X@0001:mpu
+	 */
+
+#ifdef CONFIG_MIDI
+	if((mpu_dev = isapnp_find_dev(bus,
+				ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+	{
+		mpu_dev->prepare(mpu_dev);
+
+		if((mpu_dev = activate_dev("DT0197H", "mpu", mpu_dev)))
+		{
+			show_base("DT0197H", "mpu", &mpu_dev->resource[0]);
+			mpu_config->io_base = mpu_dev->resource[0].start;
+		}
+	}
+	else
+		printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
+#endif
+
+
+	/*  @P@:Gameport
+	 */
+
+	if((jp_dev = isapnp_find_dev(bus,
+				ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+	{
+		jp_dev->prepare(jp_dev);
+
+		if((jp_dev = activate_dev("DT0197H", "gameport", jp_dev)))
+			show_base("DT0197H", "gameport", &jp_dev->resource[0]);
+	}
+	else
+		printk(KERN_ERR "sb: DT0197H panic: gameport not found\n");
+
+	/*  @H@0001:OPL3 
+	 */
+
+#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
+	if((wss_dev = isapnp_find_dev(bus,
+				ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+	{
+		wss_dev->prepare(wss_dev);
+
+		/* Let's disable IRQ and DMA for WSS device */
+
+		wss_dev->irq_resource[0].flags = 0;
+		wss_dev->dma_resource[0].flags = 0;
+
+		if((wss_dev = activate_dev("DT0197H", "opl3", wss_dev)))
+			show_base("DT0197H", "opl3", &wss_dev->resource[0]);
+	}
+	else
+		printk(KERN_ERR "sb: DT0197H panic: opl3 not found\n");
+#endif
+
+	printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner <twerner@intercomm.de>\n");
+
+	return(sb_dev);
+}
+
 /* Specific support for awe will be dropped when:
  * a) The new awe_wawe driver with PnP support will be introduced in the kernel
  * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-)
@@ -491,12 +577,14 @@
 	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0,	&sb_init_awe,		"Sound Blaster AWE 64" },
 	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0,	&sb_init_awe,		"Sound Blaster AWE 64" },
 	{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0,	&sb_init_awe,		"Sound Blaster AWE 64" },
+	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV,	&sb_init_ess,		"ESS 1688" },
 	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV,	&sb_init_ess,		"ESS 1868" },
 	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV,	&sb_init_ess,		"ESS 1868" },
 	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV,	&sb_init_ess,		"ESS 1869" },
 	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV,	&sb_init_ess,		"ESS 1878" },
 	{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV,	&sb_init_ess,		"ESS 1879" },
 	{ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0,	&sb_init_cmi,		"CMI 8330 SoundPRO" },
+	{ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0,	&sb_init_diamond,	"Diamond DT0197H" },
 	{0}
 };
 
@@ -538,7 +626,7 @@
    Should this be fixed? - azummo
 */
 
-static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) 
+int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) 
 {
 	int i;
 
@@ -594,65 +682,55 @@
 }
 #endif
 
-int init_module(void)
+static int __init init_sb(void)
 {
 	printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
-	if (mad16 == 0 && trix == 0 && pas2 == 0 && support == 0)
-	{
-		/* Please remember that even with CONFIG_ISAPNP defined one should still be
-			able to disable PNP support for this single driver!
-		*/
+	/* Please remember that even with CONFIG_ISAPNP defined one should still be
+		able to disable PNP support for this single driver!
+	*/
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE			
-		if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) )
-		{
-			printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
-			isapnp = 0;
-		}
+	if(isapnp && (sb_probe_isapnp(&cfg, &cfg_mpu) < 0) ) {
+		printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
+		isapnp = 0;
+	}
 #endif
-		if(isapnp == 0)
-		{
-			if (io == -1 || dma == -1 || irq == -1)
-			{
-				printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
-				return -EINVAL;
-			}
 
-			config.io_base	= io;
-			config.irq	= irq;
-			config.dma	= dma;
-			config.dma2	= dma16;
-		}
+	if( isapnp == 0 ) {
+		cfg.io_base	= io;
+		cfg.irq		= irq;
+		cfg.dma		= dma;
+		cfg.dma2	= dma16;
+	}
 
-		config.card_subtype = type;
+	cfg.card_subtype = type;
 
-		if (!probe_sb(&config))
-			return -ENODEV;
-		attach_sb_card(&config);
-	
-		if(config.slots[0]==-1)
-			return -ENODEV;
+	if (!probe_sb(&cfg))
+		return -ENODEV;
+	attach_sb_card(&cfg);
 
-		if (isapnp == 0) 
-			config_mpu.io_base = mpu_io;
-		if (probe_sbmpu(&config_mpu))
-			sbmpu = 1;
-		if (sbmpu)
-			attach_sbmpu(&config_mpu);
-	}
-	SOUND_LOCK;
+	if(cfg.slots[0]==-1)
+		return -ENODEV;
+		
+	if (isapnp == 0) 
+		cfg_mpu.io_base = mpu_io;
+	if (probe_sbmpu(&cfg_mpu))
+		sbmpu = 1;
+	if (sbmpu)
+		attach_sbmpu(&cfg_mpu);
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_sb(void)
 {
-	if (smw_free)
+	if (smw_free) {
 		vfree(smw_free);
-	if (!mad16 && !trix && !pas2 && !support)
-		unload_sb(&config);
+		smw_free = NULL;
+	}
+	unload_sb(&cfg);
 	if (sbmpu)
-		unload_sbmpu(&config_mpu);
+		unload_sbmpu(&cfg_mpu);
 	SOUND_LOCK_END;
 
 	if(sb_dev)	sb_dev->deactivate(sb_dev);
@@ -662,28 +740,23 @@
 	if(wss_dev)	wss_dev->deactivate(wss_dev);
 }
 
-#else
+module_init(init_sb);
+module_exit(cleanup_sb);
 
-#ifdef CONFIG_SM_GAMES
-int             sm_games = 1;
-#else
-int             sm_games = 0;
-#endif
-#ifdef CONFIG_SB_ACER
-int             acer = 1;
-#else
-int             acer = 0;
-#endif
-#endif
+#ifndef MODULE
+static int __init setup_sb(char *str)
+{
+	/* io, irq, dma, dma2 */
+	int ints[5];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma16	= ints[4];
 
-EXPORT_SYMBOL(sb_dsp_init);
-EXPORT_SYMBOL(sb_dsp_detect);
-EXPORT_SYMBOL(sb_dsp_unload);
-EXPORT_SYMBOL(sb_dsp_disable_midi);
-EXPORT_SYMBOL(attach_sb_card);
-EXPORT_SYMBOL(probe_sb);
-EXPORT_SYMBOL(unload_sb);
-EXPORT_SYMBOL(sb_be_quiet);
-EXPORT_SYMBOL(attach_sbmpu);
-EXPORT_SYMBOL(probe_sbmpu);
-EXPORT_SYMBOL(unload_sbmpu);
+	return 1;
+}
+__setup("sb=", setup_sb);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.3.49/linux/drivers/sound/sb_common.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/sb_common.c	Tue Mar  7 13:40:24 2000
@@ -9,25 +9,42 @@
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
  *                       for full duplex support ( only sb16 by now )
  * Rolf Fokkens:	 Added (BETA?) support for ES1887 chips.
  * (fokkensr@vertis.nl)	 Which means: You can adjust the recording levels.
+ *
+ * 2000/01/18 - separated sb_card and sb_common -
+ * Jeff Garzik <jgarzik@mandrakesoft.com>
+ *
  */
+
+/* FIXME: *grr* why can't the f**in Makefile do this for me ? */
+#define EXPORT_SYMTAB
+
 #include <linux/config.h>
-#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
 
 #include "sound_config.h"
 #include "sound_firmware.h"
+#include "soundmodule.h"
+
+#include "mpu401.h"
 
 #include "sb_mixer.h"
 #include "sb.h"
-
 #include "sb_ess.h"
 
+/*
+ * global module flag
+ */
+
+int sb_be_quiet = 0;
+
 static sb_devc *detected_devc = NULL;	/* For communication from probe to init */
 static sb_devc *last_devc = NULL;	/* For MPU401 initialization */
 
@@ -39,6 +56,16 @@
 	0, 1, 0, 2, 0, 3, 0, 4
 };
 
+/* Do acer notebook init? */
+int acer = 0;
+
+/* soundman games? */
+int sm_games = 0;
+
+extern int esstype;
+
+void *smw_free = NULL;
+
 /*
  * Jazz16 chipset specific control variables
  */
@@ -1033,8 +1060,6 @@
 #ifdef MODULE
 	if (!smw_ucode)
 	{
-		extern void *smw_free;
-
 		smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode);
 		smw_free = smw_ucode;
 	}
@@ -1272,3 +1297,17 @@
 #endif
 	unload_uart401(hw_config);
 }
+
+MODULE_PARM(acer, "i");
+MODULE_PARM(sm_games, "i");
+MODULE_PARM(esstype, "i");
+
+EXPORT_SYMBOL(sb_dsp_init);
+EXPORT_SYMBOL(sb_dsp_detect);
+EXPORT_SYMBOL(sb_dsp_unload);
+EXPORT_SYMBOL(sb_dsp_disable_midi);
+EXPORT_SYMBOL(sb_be_quiet);
+EXPORT_SYMBOL(attach_sbmpu);
+EXPORT_SYMBOL(probe_sbmpu);
+EXPORT_SYMBOL(unload_sbmpu);
+EXPORT_SYMBOL(smw_free);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c
--- v2.3.49/linux/drivers/sound/sgalaxy.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/sgalaxy.c	Tue Mar  7 13:40:24 2000
@@ -9,8 +9,8 @@
  *    Aztech Sound Galaxy Washington 16
  *
  * Based on cs4232.c by Hannu Savolainen and Alan Cox.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -18,11 +18,14 @@
  * for more info.
  */
 
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 
+#include "ad1848.h"
+
 static void sleep( unsigned howlong )
 {
 	current->state   = TASK_INTERRUPTIBLE;
@@ -79,10 +82,9 @@
 
 #define ai_sgbase    driver_use_1
 
-int probe_sgalaxy( struct address_info *ai )
+static int __init probe_sgalaxy( struct address_info *ai )
 {
-	if ( check_region( ai->io_base, 8 ) )
-	{
+	if ( check_region( ai->io_base, 8 ) ) {
 		printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
 		return 0;
 	}
@@ -90,8 +92,7 @@
 	if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) )
 		return probe_ms_sound(ai);  /* The card is already active, check irq etc... */
 
-	if ( check_region( ai->ai_sgbase, 0x10 ) )
-	{
+	if ( check_region( ai->ai_sgbase, 0x10 ) ) {
 		printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
 		return 0;
 	}
@@ -108,7 +109,7 @@
       	return probe_ms_sound(ai);
 }
 
-void attach_sgalaxy( struct address_info *ai )
+static void __init attach_sgalaxy( struct address_info *ai )
 {
 	int n;
 	
@@ -117,27 +118,26 @@
 	attach_ms_sound( ai );
 	n=ai->slots[0];
 	
-	if (n!=-1 && audio_devs[n]->mixer_dev != -1 )
-	{
+	if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
 		AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE );   /* Line-in */
 		AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH );  /* FM+Wavetable*/
 		AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD );     /* CD */
 	}
 }
 
-void unload_sgalaxy( struct address_info *ai )
+static void __exit unload_sgalaxy( struct address_info *ai )
 {
 	unload_ms_sound( ai );
 	release_region( ai->ai_sgbase, 0x10 );
 }
 
-#ifdef MODULE
+static struct address_info cfg;
 
-int   io       = -1;
-int   irq      = -1;
-int   dma      = -1;
-int   dma2     = -1;
-int   sgbase   = -1;
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma2	= -1;
+static int __initdata sgbase	= -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
@@ -145,38 +145,52 @@
 MODULE_PARM(dma2,"i");
 MODULE_PARM(sgbase,"i");
 
-EXPORT_NO_SYMBOLS;
-
-struct address_info ai;
-
-
-int init_module(void)
+static int __init init_sgalaxy(void)
 {
-	if ( io==-1 || irq==-1 || dma==-1 || sgbase==-1 )
-	{
+	cfg.io_base   = io;
+	cfg.irq       = irq;
+	cfg.dma       = dma;
+	cfg.dma2      = dma2;
+	cfg.ai_sgbase = sgbase;
+
+	if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
 		printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
 		return -EINVAL;
 	}
 
-	ai.io_base   = io;
-	ai.irq       = irq;
-	ai.dma       = dma;
-	ai.dma2      = dma2;
-	ai.ai_sgbase = sgbase;
-
-	if ( probe_sgalaxy( &ai )==0 )
+	if ( probe_sgalaxy(&cfg) == 0 )
 		return -ENODEV;
 
-	attach_sgalaxy( &ai );
+	attach_sgalaxy(&cfg);
 
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_sgalaxy(void)
 {
-	unload_sgalaxy( &ai );
+	unload_sgalaxy(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_sgalaxy);
+module_exit(cleanup_sgalaxy);
+
+#ifndef MODULE
+static int __init setup_sgalaxy(char *str)
+{
+	/* io, irq, dma, dma2, sgbase */
+	int ints[6];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma2	= ints[4];
+	sgbase	= ints[5];
+
+	return 1;
+}
+
+__setup("sgalaxy=", setup_sgalaxy);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c
--- v2.3.49/linux/drivers/sound/softoss.c	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/softoss.c	Tue Mar  7 13:40:24 2000
@@ -11,9 +11,12 @@
  * for more info.
  *
  *
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer	: ioctl code reworked (vmalloc/vfree removed)
+ * Christoph Hellwig	: adapted to module_init/module_exit
  */
+
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 /*
@@ -1445,7 +1448,7 @@
 	soft_tmr_restart
 };
 
-int probe_softsyn(struct address_info *hw_config)
+static int __init probe_softsyn(struct address_info *hw_config)
 {
 	int i;
 
@@ -1484,7 +1487,7 @@
 	return 1;
 }
 
-void attach_softsyn_card(struct address_info *hw_config)
+static void __init attach_softsyn_card(struct address_info *hw_config)
 {
 	voice_alloc = &softsyn_operations.alloc;
 	synth_devs[devc->synthdev = num_synths++] = &softsyn_operations;
@@ -1497,7 +1500,7 @@
 #endif
 }
 
-void unload_softsyn(struct address_info *hw_config)
+static void __exit unload_softsyn(struct address_info *hw_config)
 {
 	if (!softsynth_loaded)
 		return;
@@ -1506,25 +1509,25 @@
 	reset_samples(devc);
 }
 
-#ifdef MODULE
-
-static struct address_info config;
+static struct address_info cfg;
 
-int init_module(void)
+static int __init init_softoss(void)
 {
 	printk(KERN_INFO "SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n");
-	if (!probe_softsyn(&config))
+	if (!probe_softsyn(&cfg))
 		return -ENODEV;
-	attach_softsyn_card(&config);
+	attach_softsyn_card(&cfg);
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_softoss(void)
 {
-	unload_softsyn(&config);
+	unload_softsyn(&cfg);
 	sound_unload_synthdev(devc->synthdev);
 	sound_unload_timerdev(devc->timerdev);
 	SOUND_LOCK_END;
 }
-#endif /* MODULE */
+
+module_init(init_softoss);
+module_exit(cleanup_softoss);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v2.3.49/linux/drivers/sound/sound_calls.h	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sound/sound_calls.h	Tue Mar  7 13:40:24 2000
@@ -76,10 +76,6 @@
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
 void MIDIbuf_init(void);
 
-/*
- *
- *	Misc calls from various sources
- */
 
 /*	From soundcard.c	*/
 void request_sound_timer (int count);
@@ -87,237 +83,16 @@
 void conf_printf(char *name, struct address_info *hw_config);
 void conf_printf2(char *name, int base, int irq, int dma, int dma2);
 
-/*	From opl3.c	*/
-int opl3_detect (int ioaddr, int *osp);
-int opl3_init(int ioaddr, int *osp);
-
-/*	From sb_card.c	*/
-void attach_sb_card(struct address_info *hw_config);
-int probe_sb(struct address_info *hw_config);
-
-/*	From sb_common.c */
-void sb_dsp_disable_midi(int port);
-void sb_dsp_disable_recording(int port);
-void attach_sbmpu (struct address_info *hw_config);
-int probe_sbmpu (struct address_info *hw_config);
-void unload_sbmpu (struct address_info *hw_config);
-
-/*	From uart401.c */
-void attach_uart401 (struct address_info *hw_config);
-int probe_uart401 (struct address_info *hw_config);
-void unload_uart401 (struct address_info *hw_config);
-void uart401intr (int irq, void *dev_id, struct pt_regs * dummy);
-
-/*	From adlib_card.c	*/
-void attach_adlib_card(struct address_info *hw_config);
-int probe_adlib(struct address_info *hw_config);
-
-/*	From pas_card.c	*/
-void attach_pas_card(struct address_info *hw_config);
-int probe_pas(struct address_info *hw_config);
-int pas_set_intr(int mask);
-int pas_remove_intr(int mask);
-unsigned char pas_read(int ioaddr);
-void pas_write(unsigned char data, int ioaddr);
-
-/*	From pas_audio.c */
-void pas_pcm_interrupt(unsigned char status, int cause);
-void pas_pcm_init(struct address_info *hw_config);
-
-/*	From pas_mixer.c */
-int pas_init_mixer(void);
-
-/*	From pas_midi.c */
-void pas_midi_init(void);
-void pas_midi_interrupt(void);
-
-/*	From gus_card.c */
-void attach_gus_card(struct address_info * hw_config);
-int probe_gus(struct address_info *hw_config);
-int gus_set_midi_irq(int num);
-void gusintr(int irq, void *dev_id, struct pt_regs * dummy);
-void attach_gus_db16(struct address_info * hw_config);
-int probe_gus_db16(struct address_info *hw_config);
-
-/*	From gus_wave.c */
-int gus_wave_detect(int baseaddr);
-void gus_wave_init(struct address_info *hw_config);
-void gus_wave_unload (struct address_info *hw_config);
-void gus_voice_irq(void);
-void gus_write8(int reg, unsigned int data);
-void guswave_dma_irq(void);
-void gus_delay(void);
-int gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg);
-void gus_timer_command (unsigned int addr, unsigned int val);
-
-/*	From gus_midi.c */
-void gus_midi_init(struct address_info *hw_config);
-void gus_midi_interrupt(int dummy);
-
-/*	From mpu401.c */
-void attach_mpu401(struct address_info * hw_config);
-int probe_mpu401(struct address_info *hw_config);
-int intchk_mpu401(void *dev_id);
-void mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
-
-/*	From uart6850.c */
-void attach_uart6850(struct address_info * hw_config);
-int probe_uart6850(struct address_info *hw_config);
-
-/*	From opl3.c */
-void enable_opl3_mode(int left, int right, int both);
-
-/* 	From ics2101.c */
-int ics2101_mixer_init(void);
-
 /*	From sound_timer.c */
 void sound_timer_interrupt(void);
 void sound_timer_syncinterval(unsigned int new_usecs);
 
-/*	From ad1848.c */
-int ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp);
-void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma);
-
-int ad1848_detect (int io_base, int *flags, int *osp);
-#define AD_F_CS4231	0x0001	/* Returned if a CS4232 (or compatible) detected */
-#define AD_F_CS4248	0x0001	/* Returned if a CS4248 (or compatible) detected */
-
-int	 ad1848_control(int cmd, int arg);
-#define		AD1848_SET_XTAL		1
-#define		AD1848_MIXER_REROUTE	2
-#define AD1848_REROUTE(oldctl, newctl) \
-		ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl))
-
-void adintr(int irq, void *dev_id, struct pt_regs * dummy);
-void attach_ms_sound(struct address_info * hw_config);
-int probe_ms_sound(struct address_info *hw_config);
-
-/* 	From pss.c */
-int probe_pss (struct address_info *hw_config);
-void attach_pss (struct address_info *hw_config);
-int probe_pss_mpu (struct address_info *hw_config);
-void attach_pss_mpu (struct address_info *hw_config);
-int probe_pss_mss (struct address_info *hw_config);
-void attach_pss_mss (struct address_info *hw_config);
-
-/* 	From sscape.c */
-int probe_sscape (struct address_info *hw_config);
-void attach_sscape (struct address_info *hw_config);
-int probe_ss_ms_sound (struct address_info *hw_config);
-void attach_ss_ms_sound(struct address_info * hw_config);
-
-/* From ad1816.c */
-void unload_ad1816(struct address_info *hw_info);
-int probe_ad1816 (struct address_info *hw_config);
-void attach_ad1816 (struct address_info *hw_config);
+/*      From midi_synth.c       */
+void do_midi_msg (int synthno, unsigned char *msg, int mlen);
 
-/* From aedsp16.c */
+#ifdef FIXED_LOWLEVEL_SOUND
+/*	From aedsp16.c */
 int InitAEDSP16_SBPRO(struct address_info *hw_config);
 int InitAEDSP16_MSS(struct address_info *hw_config);
 int InitAEDSP16_MPU401(struct address_info *hw_config);
-
-/*	From midi_synth.c	*/
-void do_midi_msg (int synthno, unsigned char *msg, int mlen);
-
-/*	From trix.c	*/
-void attach_trix_wss (struct address_info *hw_config);
-int probe_trix_wss (struct address_info *hw_config);
-void attach_trix_sb (struct address_info *hw_config);
-int probe_trix_sb (struct address_info *hw_config);
-void attach_trix_mpu (struct address_info *hw_config);
-int probe_trix_mpu (struct address_info *hw_config);
-
-/*	From mad16.c	*/
-void attach_mad16 (struct address_info *hw_config);
-int probe_mad16 (struct address_info *hw_config);
-void attach_mad16_mpu (struct address_info *hw_config);
-int probe_mad16_mpu (struct address_info *hw_config);
-
-/*	Unload routines from various source files*/
-void unload_pss(struct address_info *hw_info);
-void unload_pss_mpu(struct address_info *hw_info);
-void unload_pss_mss(struct address_info *hw_info);
-void unload_mad16(struct address_info *hw_info);
-void unload_mad16_mpu(struct address_info *hw_info);
-void unload_adlib(struct address_info *hw_info);
-void unload_pas(struct address_info *hw_info);
-void unload_mpu401(struct address_info *hw_info);
-void unload_maui(struct address_info *hw_info);
-void unload_uart6850(struct address_info *hw_info);
-void unload_sb(struct address_info *hw_info);
-void unload_sb16(struct address_info *hw_info);
-void unload_sb16midi(struct address_info *hw_info);
-void unload_gus_db16(struct address_info *hw_info);
-void unload_ms_sound(struct address_info *hw_info);
-void unload_gus(struct address_info *hw_info);
-void unload_sscape(struct address_info *hw_info);
-void unload_ss_ms_sound(struct address_info *hw_info);
-void unload_trix_wss(struct address_info *hw_info);
-void unload_trix_sb(struct address_info *hw_info);
-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 */
-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 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);
-int probe_maui(struct address_info *hw_config);
-
-/*	From v_midi.c */
-void attach_v_midi (struct address_info *hw_config);
-int probe_v_midi (struct address_info *hw_config);
-void unload_v_midi (struct address_info *hw_config);
-
-/*	From vidc.c */
-void attach_vidc(struct address_info *hw_config);
-int probe_vidc(struct address_info *hw_config);
-void unload_vidc(struct address_info *hw_config);
-
-/*	From waveartist.c */
-void attach_waveartist(struct address_info *hw_config);
-int probe_waveartist(struct address_info *hw_config);
-void unload_waveartist(struct address_info *hw_config);
-
-/*	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 */
-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);
-int virtual_midi_enable (void);
-int virtual_midi_disable (void);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v2.3.49/linux/drivers/sound/sound_config.h	Sat Feb 26 22:31:49 2000
+++ linux/drivers/sound/sound_config.h	Tue Mar  7 13:40:24 2000
@@ -46,18 +46,6 @@
 #define CONFIG_PAS_BASE	0x388
 #endif
 
-#if defined(CONFIG_SB16_DMA) && !defined(CONFIG_SB_DMA2)
-#  define CONFIG_SB_DMA2 CONFIG_SB16_DMA
-#endif
-
-#if defined(SB16MIDI_BASE) && !defined(CONFIG_SB_MPU_BASE)
-#   define CONFIG_SB_MPU_BASE SB16MIDI_BASE
-#endif
-
-#ifndef CONFIG_SB_MPU_IRQ
-#  define CONFIG_SB_MPU_IRQ CONFIG_SB_IRQ
-#endif
-
 /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
    driver. (There is no need to alter this) */
 #define SEQ_MAX_QUEUE	1024
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c
--- v2.3.49/linux/drivers/sound/sound_syms.c	Mon Jul  5 19:58:25 1999
+++ linux/drivers/sound/sound_syms.c	Tue Mar  7 13:40:24 2000
@@ -46,8 +46,6 @@
 
 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.49/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.3.49/linux/drivers/sound/soundcard.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/sound/soundcard.c	Tue Mar  7 13:40:24 2000
@@ -2,24 +2,24 @@
  * linux/drivers/sound/soundcard.c
  *
  * Sound card driver for Linux
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ *
+ *
+ * Thomas Sailer     : ioctl code reworked (vmalloc/vfree removed)
  *                   integrated sound_switch.c
- * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat,
+ * Stefan Reinauer   : integrated /proc/sound (equals to /dev/sndstat,
  *                   which should disappear in the near future)
- * Eric Dumas      : devfs support (22-Jan-98) <dumas@linux.eu.org> with fixups
- *                   by C. Scott Ananian <cananian@alumni.princeton.edu>
- * Richard Gooch   : moved common (non OSS-specific) devices to sound_core.c
- *
- * Rob Riggs		Added persistent DMA buffers support (1998/10/17)
+ * Eric Dumas	     : devfs support (22-Jan-98) <dumas@linux.eu.org> with
+ *                   fixups by C. Scott Ananian <cananian@alumni.princeton.edu>
+ * Richard Gooch     : moved common (non OSS-specific) devices to sound_core.c
+ * Rob Riggs	     : Added persistent DMA buffers support (1998/10/17)
+ * Christoph Hellwig : Some cleanup work (2000/03/01)
  */
 
 #include <linux/config.h>
@@ -32,7 +32,6 @@
 #include <linux/ctype.h>
 #include <linux/stddef.h>
 #include <linux/kmod.h>
-#ifdef __KERNEL__
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -41,24 +40,23 @@
 #include <linux/ioport.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
-#endif				/* __KERNEL__ */
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include "soundmodule.h"
 
+
+#if defined(CONFIG_LOWLEVEL_SOUND) && !defined MODULE
+extern void sound_preinit_lowlevel_drivers(void);
+extern void sound_init_lowlevel_drivers(void);
+#endif
+
 /* From obsolete legacy.h */
 #define SELECTED_SOUND_OPTIONS 0x0
 
 struct notifier_block *sound_locker=(struct notifier_block *)0;
 static int lock_depth = 0;
 
-#ifdef MODULE
-#define modular 1
-#else
-#define modular 0
-#endif
-
 /*
  * This ought to be moved into include/asm/dma.h
  */
@@ -76,16 +74,9 @@
 int             sound_nblocks = 0;
 
 /* Persistent DMA buffers */
-#ifdef CONFIG_SOUND_DMAP
-int		sound_dmap_flag = 1;
-#else
 int		sound_dmap_flag = 0;
-#endif
-
 static int      soundcard_configured = 0;
-
-static char     dma_alloc_map[MAX_DMA_CHANNELS] =
-{0};
+static char     dma_alloc_map[MAX_DMA_CHANNELS] = {0};
 
 #define DMA_MAP_UNAVAIL		0
 #define DMA_MAP_FREE		1
@@ -101,6 +92,8 @@
 static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
 static int num_mixer_volumes = 0;
 
+int traceinit = 0;
+
 int *load_mixer_volumes(char *name, int *levels, int present)
 {
 	int             i, n;
@@ -159,137 +152,6 @@
 	return 0;
 }
 
-static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	int len, i, drv;
-        off_t pos = 0;
-        off_t begin = 0;
-
-#ifdef MODULE
-#define MODULEPROCSTRING "Driver loaded as a module"
-#else
-#define MODULEPROCSTRING "Driver compiled into kernel"
-#endif
-
-	down_read(&uts_sem);	
-
-	len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
-		      "Load type: " MODULEPROCSTRING "\n"
-		      "Kernel: %s %s %s %s %s\n"
-		      "Config options: %x\n\nInstalled drivers: \n", 
-		      system_utsname.sysname, system_utsname.nodename, system_utsname.release, 
-		      system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
-	up_read(&uts_sem);
-	
-	for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
-		if (!sound_drivers[i].card_type)
-			continue;
-		len += sprintf(buffer + len, "Type %d: %s\n", 
-			       sound_drivers[i].card_type, sound_drivers[i].name);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-	len += sprintf(buffer + len, "\nCard config: \n");
-
-	for (i = 0; (i < num_sound_cards) && (pos <= offset + length); i++) 
-	{
-		if (!snd_installed_cards[i].card_type)
-			continue;
-		if (!snd_installed_cards[i].enabled)
-			len += sprintf(buffer + len, "(");
-		if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)
-			len += sprintf(buffer + len, "%s", sound_drivers[drv].name);
-		if (snd_installed_cards[i].config.io_base)
-			len += sprintf(buffer + len, " at 0x%x", snd_installed_cards[i].config.io_base);
-		if (snd_installed_cards[i].config.irq != 0)
-			len += sprintf(buffer + len, " irq %d", abs(snd_installed_cards[i].config.irq));
-		if (snd_installed_cards[i].config.dma != -1) {
-			len += sprintf(buffer + len, " drq %d", snd_installed_cards[i].config.dma);
-			if (snd_installed_cards[i].config.dma2 != -1)
-				len += sprintf(buffer + len, ",%d", snd_installed_cards[i].config.dma2);
-		}
-		if (!snd_installed_cards[i].enabled)
-			len += sprintf(buffer + len, ")");
-		len += sprintf(buffer + len, "\n");
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-	if (!sound_started)
-		len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n");
-	len += sprintf(buffer + len, "\nAudio devices:\n");
-	for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) {
-		if (audio_devs[i] == NULL)
-			continue;
-		len += sprintf(buffer + len, "%d: %s%s\n", i, audio_devs[i]->name, 
-			       audio_devs[i]->flags & DMA_DUPLEX ? " (DUPLEX)" : "");
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-
-	len += sprintf(buffer + len, "\nSynth devices:\n");
-	for (i = 0; (i < num_synths) && (pos <= offset + length); i++) {
-		if (synth_devs[i] == NULL)
-			continue;
-		len += sprintf(buffer + len, "%d: %s\n", i, synth_devs[i]->info->name);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-
-	len += sprintf(buffer + len, "\nMidi devices:\n");
-	for (i = 0; (i < num_midis) && (pos <= offset + length); i++) {
-		if (midi_devs[i] == NULL)
-			continue;
-		len += sprintf(buffer + len, "%d: %s\n", i, midi_devs[i]->info.name);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-
-	len += sprintf(buffer + len, "\nTimers:\n");
-
-	for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) {
-		if (sound_timer_devs[i] == NULL)
-			continue;
-		len += sprintf(buffer + len, "%d: %s\n", i, sound_timer_devs[i]->info.name);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-
-	len += sprintf(buffer + len, "\nMixers:\n");
-	for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) {
-		if (mixer_devs[i] == NULL)
-			continue;
-		len += sprintf(buffer + len, "%d: %s\n", i, mixer_devs[i]->name);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-	}
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
-        if (len > length) 
-		len = length;
-        return len;
-}
-
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
@@ -297,67 +159,6 @@
 /* 4K page size but our output routines use some slack for overruns */
 #define PROC_BLOCK_SIZE (3*1024)
 
-/*
- * basically copied from fs/proc/generic.c:proc_file_read 
- * should be removed sometime in the future together with /dev/sndstat
- * (a symlink /dev/sndstat -> /proc/sound will do as well)
- */
-static ssize_t sndstat_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
-{
-        char    *page;
-        ssize_t retval=0;
-        int     eof=0;
-        ssize_t n, count;
-        char    *start;
-
-        if (!(page = (char*) __get_free_page(GFP_KERNEL)))
-                return -ENOMEM;
-
-        while ((nbytes > 0) && !eof)
-        {
-                count = MIN(PROC_BLOCK_SIZE, nbytes);
-
-                start = NULL;
-		n = sound_proc_get_info(page, &start, *ppos, count);
-		if (n < count)
-			eof = 1;
-                        
-                if (!start) {
-                        /*
-                         * For proc files that are less than 4k
-                         */
-                        start = page + *ppos;
-                        n -= *ppos;
-                        if (n <= 0)
-                                break;
-                        if (n > count)
-                                n = count;
-                }
-                if (n == 0)
-                        break;  /* End of file */
-                if (n < 0) {
-                        if (retval == 0)
-                                retval = n;
-                        break;
-                }
-                
-                n -= copy_to_user(buf, start, n);       /* BUG ??? */
-                if (n == 0) {
-                        if (retval == 0)
-                                retval = -EFAULT;
-                        break;
-                }
-                
-                *ppos += n;     /* Move down the file */
-                nbytes -= n;
-                buf += n;
-                retval += n;
-        }
-        free_page((unsigned long) page);
-        return retval;
-}
-
-
 static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
 	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
@@ -373,10 +174,6 @@
 	
 	DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
 	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
-		ret = sndstat_file_read(file, buf, count, ppos);
-		break;
-
 	case SND_DEV_DSP:
 	case SND_DEV_DSP16:
 	case SND_DEV_AUDIO:
@@ -484,10 +281,8 @@
 	}
 	in_use++;
 
-#ifdef CONFIG_MODULES
 	notifier_call_chain(&sound_locker, 1, 0);
 	lock_depth++;
-#endif
 
 	return 0;
 }
@@ -522,10 +317,8 @@
 	}
 	in_use--;
 
-#ifdef CONFIG_MODULES
 	notifier_call_chain(&sound_locker, 0, 0);
 	lock_depth--;
-#endif
 
 	return 0;
 }
@@ -844,22 +637,13 @@
 
 	soundcard_configured = 1;
 
-	sndtable_init();	/* Initialize call tables and detect cards */
-
-
-#ifdef FIXME
-	if (sndtable_get_cardcount() == 0)
-		return;		/* No cards detected */
+#if defined(CONFIG_LOWLEVEL_SOUND) && !defined(MODULE)
+        sound_preinit_lowlevel_drivers();
+	sound_init_lowlevel_drivers();
 #endif
 
-	if (num_audiodevs || modular)	/* Audio devices present */
-	{
-		audio_init_devices();
-	}
-#ifdef CONFIG_PROC_FS
-	if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info))
-		printk(KERN_ERR "sound: registering /proc/sound failed\n");
-#endif		
+	audio_init_devices();
+
 	soundcard_register_devfs(1); /* register after we know # of devices */
 }
 
@@ -876,7 +660,6 @@
 	0
 };
 
-int traceinit = 0;
 static int dmabuf = 0;
 static int dmabug = 0;
 
@@ -892,8 +675,6 @@
 	int             i;
 #endif
 
-	trace_init=traceinit;
-	
 #ifdef HAS_BRIDGE_BUGGY_FUNC
 	if(dmabug)
 		isa_dma_bridge_buggy = dmabug;
@@ -956,7 +737,6 @@
 		sound_unload_lowlevel_drivers();
 	}
 #endif
-	sound_unload_drivers();
 	sequencer_unload();
 
 	for (i = 0; i < MAX_DMA_CHANNELS; i++)
@@ -1075,9 +855,8 @@
 
 void conf_printf(char *name, struct address_info *hw_config)
 {
-	if (!trace_init)
+	if (!traceinit)
 		return;
-
 	printk("<%s> at 0x%03x", name, hw_config->io_base);
 
 	if (hw_config->irq)
@@ -1094,7 +873,7 @@
 
 void conf_printf2(char *name, int base, int irq, int dma, int dma2)
 {
-	if (!trace_init)
+	if (!traceinit)
 		return;
 
 	printk("<%s> at 0x%03x", name, base);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h
--- v2.3.49/linux/drivers/sound/soundmodule.h	Thu May 14 10:33:17 1998
+++ linux/drivers/sound/soundmodule.h	Tue Mar  7 13:40:24 2000
@@ -2,12 +2,11 @@
 #define _SOUNDMODULE_H
 
 #include <linux/notifier.h>
+#include <linux/module.h>
 
 extern struct notifier_block *sound_locker;
 extern void sound_notifier_chain_register(struct notifier_block *);
 
-#ifdef MODULE
-
 #define SOUND_LOCK		sound_notifier_chain_register(&sound_notifier); 
 #define SOUND_LOCK_END		notifier_chain_unregister(&sound_locker, &sound_notifier)
 
@@ -27,5 +26,4 @@
 	0
 };
 
-#endif
 #endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v2.3.49/linux/drivers/sound/sscape.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/sound/sscape.c	Tue Mar  7 13:40:24 2000
@@ -2,21 +2,22 @@
  * sound/sscape.c
  *
  * Low level driver for Ensoniq SoundScape
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
- 
-/*
+ *
+ *
  * Thomas Sailer   	: ioctl code reworked (vmalloc/vfree removed)
  * Sergey Smitienko	: ensoniq p'n'p support
+ * Christoph Hellwig	: adapted to module_init/module_exit
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
@@ -30,19 +31,20 @@
 #include <linux/ctype.h>
 #include <linux/stddef.h>
 #include <linux/kmod.h>
-#ifdef __KERNEL__
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <linux/wait.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
-#endif				/* __KERNEL__ */
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 
 #include "coproc.h"
 
+#include "ad1848.h"
+#include "mpu401.h"
+
 /*
  *    I/O ports
  */
@@ -1005,7 +1007,7 @@
 	return 1;
 }
 
-static	void	sscape_pnp_init_hw(sscape_info* devc)
+static void __init sscape_pnp_init_hw(sscape_info* devc)
 {	
 	unsigned char midi_irq = 0, sb_irq = 0;
 	unsigned i;
@@ -1127,7 +1129,7 @@
 	sscape_pnp_free_dma(devc);
 }
 
-static int	detect_sscape_pnp(sscape_info* devc)
+static int __init detect_sscape_pnp(sscape_info* devc)
 {
 	long	 i, irq_bits = 0xff;
 	unsigned int d;
@@ -1240,7 +1242,7 @@
 	return 1;	
 }
 
-int probe_sscape(struct address_info *hw_config)
+static int __init probe_sscape(struct address_info *hw_config)
 {
 
 	if (sscape_detected != 0 && sscape_detected != hw_config->io_base)
@@ -1289,7 +1291,7 @@
 	return 1;
 }
 
-int probe_ss_ms_sound(struct address_info *hw_config)
+static int __init probe_ss_ms_sound(struct address_info *hw_config)
 {
 	int i, irq_bits = 0xff;
 	int ad_flags = 0;
@@ -1332,7 +1334,7 @@
 	}
 }
 
-void attach_ss_ms_sound(struct address_info *hw_config)
+static void __init attach_ss_ms_sound(struct address_info *hw_config)
 {
 	/*
 	 * This routine configures the SoundScape card for use with the
@@ -1413,13 +1415,13 @@
 
 }
 
-void unload_sscape(struct address_info *hw_config)
+static void __exit unload_sscape(struct address_info *hw_config)
 {
 	release_region(devc->base + 2, 6);
 	unload_mpu401(hw_config);
 }
 
-void unload_ss_ms_sound(struct address_info *hw_config)
+static void __exit unload_ss_ms_sound(struct address_info *hw_config)
 {
 	ad1848_unload(hw_config->io_base,
 		      hw_config->irq,
@@ -1429,18 +1431,16 @@
 	sound_unload_audiodev(hw_config->slots[0]);
 }
 
-#ifdef MODULE
-
-int             dma = -1;
-int             irq = -1;
-int             io = -1;
+static struct address_info cfg;
+static struct address_info cfg_mpu;
 
-int             mpu_irq = -1;
-int             mpu_io = -1;
-
-int		spea = -1;
-
-static int      mss = 0;
+static int __initdata spea = -1;
+static int __initdata mss = 0;
+static int __initdata dma = -1;
+static int __initdata irq = -1;
+static int __initdata io = -1;
+static int __initdata mpu_irq = -1;
+static int __initdata mpu_io = -1;
 
 MODULE_PARM(dma, "i");
 MODULE_PARM(irq, "i");
@@ -1450,63 +1450,80 @@
 MODULE_PARM(mpu_io, "i");
 MODULE_PARM(mss, "i");
 
-struct address_info config;
-struct address_info mpu_config;
-
-int init_module(void)
+static int __init init_sscape(void)
 {
 	printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-	if (dma == -1 || irq == -1 || io == -1)
-	{
-		printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n");
-		return -EINVAL;
-	}
-	if (mpu_irq == -1 && mpu_io != -1)
-	{
-		  printk(KERN_ERR "CONFIG_MPU_IRQ must be specified if CONFIG_MPU_IO is set.\n");
-		  return -EINVAL;
-	}
 	
-	devc->codec = io;
-	devc->codec_irq = irq;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.io_base = io;
+
+	cfg_mpu.irq = mpu_irq;
+	cfg_mpu.io_base = mpu_io;
+	/* WEH - Try to get right dma channel */
+        cfg_mpu.dma = dma;
+	
+	devc->codec = cfg.io_base;
+	devc->codec_irq = cfg.irq;
 	devc->codec_type = 0;
 	devc->ic_type = 0;
 	devc->raw_buf = NULL;
-	
-	config.irq = irq;
-	config.dma = dma;
-	config.io_base = io;
 
-	mpu_config.irq = mpu_irq;
-	mpu_config.io_base = mpu_io;
-	/* WEH - Try to get right dma channel */
-        mpu_config.dma = dma;
-      
-	if(spea != -1)
-	{
+	if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) {
+		printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n");
+		return -EINVAL;
+	}
+	
+	if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) {
+		printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n");
+		return -EINVAL;
+	}
+	
+	if(spea != -1) {
 		old_hardware = spea;
 		printk(KERN_INFO "Forcing %s hardware support.\n",
 			spea?"new":"old");
 	}	
-	if (probe_sscape(&mpu_config) == 0)
+	if (probe_sscape(&cfg_mpu) == 0)
 		return -ENODEV;
 
-	attach_sscape(&mpu_config);
+	attach_sscape(&cfg_mpu);
 	
-	mss = probe_ss_ms_sound(&config);
+	mss = probe_ss_ms_sound(&cfg);
 
 	if (mss)
-		attach_ss_ms_sound(&config);
+		attach_ss_ms_sound(&cfg);
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_sscape(void)
 {
 	if (mss)
-		unload_ss_ms_sound(&config);
+		unload_ss_ms_sound(&cfg);
 	SOUND_LOCK_END;
-	unload_sscape(&mpu_config);
+	unload_sscape(&cfg_mpu);
+}
+
+module_init(init_sscape);
+module_exit(cleanup_sscape);
+
+#ifndef MODULE
+static int __init setup_sscape(char *str)
+{
+	/* io, irq, dma, mpu_io, mpu_irq */
+	int ints[6];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	mpu_io	= ints[4];
+	mpu_irq	= ints[5];
+
+	return 1;
 }
 
-#endif /* MODULE */
+__setup("sscape=", setup_sscape);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.3.49/linux/drivers/sound/trident.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/sound/trident.c	Thu Mar  2 22:44:07 2000
@@ -29,6 +29,12 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.13 Mar 03 2000 Ollie Lho
+ *	new pci_* for 2.4 kernel, back ported to 2.2
+ *  v0.12 Feb 23 2000 Ollie Lho
+ *	Preliminary Recording support
+ *  v0.11.2 Feb 19 2000 Ollie Lho
+ *	removed incomplete full-dulplex support
  *  v0.11.1 Jan 28 2000 Ollie Lho
  *	small bug in setting sample rate for 4d-nx (reported by Aaron)
  *  v0.11 Jan 27 2000 Ollie Lho
@@ -58,9 +64,10 @@
  *	Clean up of low level channel register access code. (done)
  *        Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
  *	Dual AC97 codecs support (done partially, need channel binding to test)
- *	Recording support
+ *	Recording support (done)
  *	Mmap support
  *	"Channel Binding" ioctl extension
+ *	new pci device driver interface for 2.4 kernel
  */
       
 #include <linux/module.h>
@@ -85,27 +92,15 @@
 
 #include "trident.h"
 
-#undef DEBUG
-
-#define DRIVER_VERSION "0.11.1"
+#define DRIVER_VERSION "0.13"
 
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC	0x5072696E /* "Prin" */
 #define TRIDENT_STATE_MAGIC	0x63657373 /* "cess" */
 
-/* The first 32 channels are called Bank A. They are (should be) reserved
-   for MIDI synthesizer. But since that is not supported yet, we can (ab)use
-   them to play PCM samples */
-#undef ABUSE_BANK_A
-
-/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ?
-   NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW
-   channels */
-#ifdef ABUSE_BANK_A
-#define NR_HW_CH		64
-#else
+#define TRIDENT_DMA_MASK		0x3fffffff /* DMA buffer mask for pci_alloc_consist */
+
 #define NR_HW_CH		32
-#endif
 
 /* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
    have 2 SDATA_IN lines (currently) */
@@ -119,18 +114,29 @@
 
 static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
 
-struct pci_audio_info {
-	u16 vendor;
-	u16 device;
-	char *name;
+enum {
+	TRIDENT_4D_DX = 0,
+	TRIDENT_4D_NX,
+	SIS_7018
 };
 
-static struct pci_audio_info pci_audio_devices[] = {
-	{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"},
-	{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
+static char * card_names[] = {
+	"Trident 4DWave DX",
+	"Trident 4DWave NX",
+	"SiS 7018 PCI Audio"
 };
 
+static struct pci_device_id trident_pci_tbl [] __devinitdata = {
+	{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX},
+	{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018},
+};
+
+MODULE_DEVICE_TABLE (pci, trident_pci_tbl);
+
 /* "software" or virtual channel, an instance of opened /dev/dsp */
 struct trident_state {
 	unsigned int magic;
@@ -156,14 +162,15 @@
 
 		/* OSS buffer manangemeent stuff */
 		void *rawbuf;
+		dma_addr_t dma_handle;
 		unsigned buforder;
 		unsigned numfrag;
 		unsigned fragshift;
 
 		/* our buffer acts like a circular ring */
-		unsigned hwptr;		/* where dma last started, update by update_ptr */
+		unsigned hwptr;		/* where dma last started, updated by update_ptr */
 		unsigned swptr;		/* where driver last clear/filled, updated by read/write */
-		int count;		/* bytes to be comsumed by dma machine */
+		int count;		/* bytes to be comsumed or been generated by dma machine */
 		unsigned total_bytes;	/* total bytes dmaed by hardware */
 
 		unsigned error;		/* number of over/underruns */
@@ -177,22 +184,21 @@
 		/* OSS stuff */
 		unsigned mapped:1;
 		unsigned ready:1;
-		unsigned endcleared:1;
 		unsigned ossfragshift;
 		int ossmaxfrags;
 		unsigned subdivision;
-	} dma_dac, dma_adc;
+	} dmabuf;
 };
 
 /* hardware channels */
 struct trident_channel {
 	int  num;	/* channel number */
-	u32 lba;	/* reg 0xe4 */
-	u32 eso;	/* reg 0xe8 */
-	u32 delta;
-	u16 attribute;	/* reg 0xec */
+	u32 lba;	/* Loop Begine Address, where dma buffer starts */
+	u32 eso;	/* End Sample Offset, wehre dma buffer ends (in the unit of samples) */
+	u32 delta;	/* delta value, sample rate / 48k for playback, 48k/sample rate for recording */
+	u16 attribute;	/* control where PCM data go and come  */
 	u16 fm_vol;
-	u32 control;	/* reg 0xf0 */
+	u32 control;	/* signed/unsigned, 8/16 bits, mono/stereo */
 };
 
 struct trident_pcm_bank_address {
@@ -234,7 +240,6 @@
 	spinlock_t lock;
 
 	/* PCI device stuff */
-	struct pci_audio_info *pci_info;
 	struct pci_dev * pci_dev;
 	u16 pci_id;
 
@@ -422,9 +427,6 @@
 	if (bank->bitmap == ~0UL) {
 		/* no more free channels avaliable */
 		printk(KERN_ERR "trident: no more channels available on Bank B.\n");
-#ifdef ABUSE_BANK_A
-		goto bank_a;
-#endif
 		return NULL;
 	}
 	for (idx = 31; idx >= 0; idx--) {
@@ -435,26 +437,6 @@
 			return channel;
 		}
 	}
-
-#ifdef ABUSE_BANK_A
-	/* channels in Bank A should be reserved for synthesizer 
-	   not for normal use (channels in Bank A can't record) */
- bank_a:
-	bank = &card->banks[BANK_A];
-	if (bank->bitmap == ~0UL) {
-		/* no more free channels avaliable */
-		printk(KERN_ERR "trident: no more channels available on Bank A.\n");
-		return NULL;
-	}
-	for (idx = 31; idx >= 0; idx--) {
-		if (!(bank->bitmap & (1 << idx))) {
-			struct trident_channel *channel = &bank->channels[idx];
-			banks->bitmap |= 1 << idx;
-			channel->num = idx;
-			return channels;
-		}
-	}
-#endif
 	return NULL;
 }
 
@@ -462,13 +444,8 @@
 {
 	int bank;
 
-#ifdef ABUSE_BANK_A
-	if (channel < 0 || channel > 63)
-		return;
-#else
 	if (channel < 31 || channel > 63)
 		return;
-#endif
 
 	bank = channel >> 5;
 	channel = channel & 0x1f;
@@ -497,15 +474,12 @@
 }
 
 /* called with spin lock held */
-static int trident_write_voice_regs(struct trident_state *state, unsigned int rec)
+static int trident_write_voice_regs(struct trident_state *state)
 {
 	unsigned int data[CHANNEL_REGS + 1];
 	struct trident_channel *channel;
 
-	if (rec)
-		channel = state->dma_adc.channel;
-	else
-		channel = state->dma_dac.channel;
+	channel = state->dmabuf.channel;
 
 	data[1] = channel->lba;
 	data[4] = channel->control;
@@ -534,7 +508,7 @@
 	return trident_load_channel_registers(state->card, data, channel->num);
 }
 
-static int compute_rate(u32 rate)
+static int compute_rate_play(u32 rate)
 {
 	int delta;
 	/* We special case 44100 and 8000 since rounding with the equation
@@ -552,10 +526,25 @@
 	return delta;
 }
 
+static int compute_rate_rec(u32 rate)
+{
+	int delta;
+
+	if (rate == 44100)
+		delta = 0x116a;
+	else if (rate == 8000)
+		delta = 0x6000;
+	else if (rate == 48000)
+		delta = 0x1000;
+	else
+		delta = ((48000 << 12) / rate) & 0x0000ffff;
+
+	return delta;
+}
 /* set playback sample rate */
 static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate)
 {	
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 
 	if (rate > 48000)
 		rate = 48000;
@@ -563,9 +552,9 @@
 		rate = 4000;
 
 	dmabuf->rate = rate;
-	dmabuf->channel->delta = compute_rate(rate);
+	dmabuf->channel->delta = compute_rate_play(rate);
 
-	trident_write_voice_regs(state, 0);
+	trident_write_voice_regs(state);
 
 #ifdef DEBUG
 	printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
@@ -577,16 +566,17 @@
 /* set recording sample rate */
 static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate)
 {
-	struct dmabuf *dmabuf = &state->dma_adc;
+	struct dmabuf *dmabuf = &state->dmabuf;
+
 	if (rate > 48000)
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
 
 	dmabuf->rate = rate;
-	dmabuf->channel->delta = compute_rate(rate);
+	dmabuf->channel->delta = compute_rate_rec(rate);
 
-	trident_write_voice_regs(state, 1);
+	trident_write_voice_regs(state);
 
 #ifdef DEBUG
 	printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
@@ -597,18 +587,18 @@
 /* prepare channel attributes for playback */ 
 static void trident_play_setup(struct trident_state *state)
 {
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	struct trident_channel *channel = dmabuf->channel;
 
 	channel->lba = virt_to_bus(dmabuf->rawbuf);
-	channel->delta = compute_rate(dmabuf->rate);
+	channel->delta = compute_rate_play(dmabuf->rate);
 
 	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
 	channel->eso -= 1;
 
 	if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
-		/* FIXME: channel attributes are configured by ioctls, but it is not implemented
-		   so just set to ZERO for the moment */
+		/* FIXME: channel attributes are configured by ioctls, but it is not
+		   implemented so just set to ZERO for the moment */
 		channel->attribute = 0;
 	} else {
 		channel->attribute = 0;
@@ -631,7 +621,7 @@
 	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
 	       channel->lba, channel->delta, channel->eso, channel->control);
 #endif
-	trident_write_voice_regs(state, 0);
+	trident_write_voice_regs(state);
 }
 
 /* prepare channel attributes for recording */
@@ -639,7 +629,7 @@
 {
 	u16 w;
 	struct trident_card *card = state->card;
-	struct dmabuf *dmabuf = &state->dma_adc;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	struct trident_channel *channel = dmabuf->channel;
 
 	/* Enable AC-97 ADC (capture) */
@@ -651,25 +641,30 @@
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
 		w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
 		outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+		/* enable and set record channel */
+		outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
 		w = inw(TRID_REG(card, T4D_MISCINT));
 		outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));
+		/* enable and set record channel */
+		outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
 		break;
 	default:
 		return;
 	}
 
 	channel->lba = virt_to_bus(dmabuf->rawbuf);
-	channel->delta = compute_rate(dmabuf->rate);
+	channel->delta = compute_rate_rec(dmabuf->rate);
 
 	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
 	channel->eso -= 1;
 
 	if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
-		/* FIXME: channel attributes are configured by ioctls, but it is not implemented
-		   so just set to ZERO for the moment */
-		channel->attribute = 0;
+		/* FIXME: channel attributes are configured by ioctls, but it is not
+		   implemented so just set to 0x8a80 for the moment, record from PCM L/R
+		   input and mono = (left + right + 1)/2*/
+		channel->attribute = 0x8A80;
 	} else {
 		channel->attribute = 0;
 	}
@@ -691,21 +686,16 @@
 	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
 	       channel->lba, channel->delta, channel->eso, channel->control);
 #endif
-	trident_write_voice_regs(state, 1);
+	trident_write_voice_regs(state);
 }
 
 /* get current playback/recording dma buffer pointer (byte offset from LBA),
    called with spinlock held! */
-extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec)
+extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state)
 {
-	struct dmabuf *dmabuf;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	u32 cso;
 
-	if (rec)
-		dmabuf = &state->dma_adc;
-	else
-		dmabuf = &state->dma_dac;
-
 	if (!dmabuf->enable)
 		return 0;
 
@@ -727,7 +717,8 @@
 	}
 
 #ifdef DEBUG
-	printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n",
+	printk("trident: trident_get_dma_addr: chip reported channel: %d, "
+	       "cso = 0x%04x\n",
 	       dmabuf->channel->num, cso);
 #endif
 	/* ESO and CSO are in units of Samples, convert to byte offset */
@@ -739,11 +730,11 @@
 /* Stop recording (lock held) */
 extern __inline__ void __stop_adc(struct trident_state *state)
 {
-	struct dmabuf *dmabuf = &state->dma_adc;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned int chan_num = dmabuf->channel->num;
 	struct trident_card *card = state->card;
 
-	dmabuf->enable &= ~DMA_RUNNING;
+	dmabuf->enable &= ~ADC_RUNNING;
 	trident_stop_voice(card, chan_num);
 	trident_disable_voice_irq(card, chan_num);
 }
@@ -760,16 +751,14 @@
 
 static void start_adc(struct trident_state *state)
 {
-	struct dmabuf *dmabuf = &state->dma_adc;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned int chan_num = dmabuf->channel->num;
 	struct trident_card *card = state->card;
 	unsigned long flags;
 
 	spin_lock_irqsave(&card->lock, flags);
-	if ((dmabuf->mapped || 
-	     dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize))
-	    && dmabuf->ready) {
-		dmabuf->enable |= DMA_RUNNING;
+	if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) {
+		dmabuf->enable |= ADC_RUNNING;
 		trident_enable_voice_irq(card, chan_num);
 		trident_start_voice(card, chan_num);
 	}
@@ -779,11 +768,11 @@
 /* stop playback (lock held) */
 extern __inline__ void __stop_dac(struct trident_state *state)
 {
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned int chan_num = dmabuf->channel->num;
 	struct trident_card *card = state->card;
 
-	dmabuf->enable &= ~DMA_RUNNING;
+	dmabuf->enable &= ~DAC_RUNNING;
 	trident_stop_voice(card, chan_num);
 	trident_disable_voice_irq(card, chan_num);
 }
@@ -800,14 +789,14 @@
 
 static void start_dac(struct trident_state *state)
 {
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned int chan_num = dmabuf->channel->num;
 	struct trident_card *card = state->card;
 	unsigned long flags;
 
 	spin_lock_irqsave(&card->lock, flags);
 	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
-		dmabuf->enable |= DMA_RUNNING;
+		dmabuf->enable |= DAC_RUNNING;
 		trident_enable_voice_irq(card, chan_num);
 		trident_start_voice(card, chan_num);
 	}
@@ -818,39 +807,27 @@
 #define DMABUF_MINORDER 1
 
 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct trident_state *state, unsigned rec)
+static int alloc_dmabuf(struct trident_state *state)
 {
-	struct dmabuf *dmabuf;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	void *rawbuf;
 	int order;
 	unsigned long map, mapend;
 
-	if (rec)
-		dmabuf  = &state->dma_adc;
-	else
-		dmabuf  = &state->dma_dac;
-
 	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
 	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-		if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
+		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
+						   PAGE_SIZE << order,
+						   &dmabuf->dma_handle)))
 			break;
 	if (!rawbuf)
 		return -ENOMEM;
+
 #ifdef DEBUG
 	printk("trident: allocated %ld (order = %d) bytes at %p\n",
 	       PAGE_SIZE << order, order, rawbuf);
 #endif
 
-	/* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address
-	   (LBA) which limits the address space to 1 (2) GB, bad T^2 design */
-	if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) {
-		printk(KERN_ERR "trident: DMA buffer beyond 1 GB; "
-		       "bus address = 0x%lx, size = %ld\n",
-		       virt_to_bus(rawbuf), PAGE_SIZE << order);
-		free_pages((unsigned long)rawbuf, order);
-		return -ENOMEM;
-	}
-
 	dmabuf->ready  = dmabuf->mapped = 0;
 	dmabuf->rawbuf = rawbuf;
 	dmabuf->buforder = order;
@@ -864,16 +841,18 @@
 }
 
 /* free DMA buffer */
-static void dealloc_dmabuf(struct dmabuf *dmabuf)
+static void dealloc_dmabuf(struct trident_state *state)
 {
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long map, mapend;
 
 	if (dmabuf->rawbuf) {
 		/* undo marking the pages as reserved */
 		mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
 		for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++)
-			clear_bit(PG_reserved, &mem_map[map].flags);	
-		free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder);
+			clear_bit(PG_reserved, &mem_map[map].flags);
+		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
+				    dmabuf->rawbuf, dmabuf->dma_handle);
 	}
 	dmabuf->rawbuf = NULL;
 	dmabuf->mapped = dmabuf->ready = 0;
@@ -881,25 +860,20 @@
 
 static int prog_dmabuf(struct trident_state *state, unsigned rec)
 {
-	struct dmabuf *dmabuf;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned bytepersec;
 	unsigned bufsize;
 	unsigned long flags;
 	int ret;
 
-	if (rec)
-		dmabuf = &state->dma_adc;
-	else
-		dmabuf = &state->dma_dac;
-
 	spin_lock_irqsave(&state->card->lock, flags);
-	dmabuf->hwptr  = dmabuf->swptr = dmabuf->total_bytes = 0;
-	dmabuf->count  = dmabuf->error = dmabuf->endcleared  = 0;
+	dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0;
+	dmabuf->count = dmabuf->error = 0;
 	spin_unlock_irqrestore(&state->card->lock, flags);
 
 	/* allocate DMA buffer if not allocated yet */
 	if (!dmabuf->rawbuf)
-		if ((ret = alloc_dmabuf(state, rec)))
+		if ((ret = alloc_dmabuf(state)))
 			return ret;
 
 	/* FIXME: figure out all this OSS fragment stuff */
@@ -958,7 +932,7 @@
 */
 static void trident_clear_tail(struct trident_state *state)
 {
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned swptr;
 	unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;
 	unsigned int len;
@@ -971,7 +945,6 @@
 	if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)
 		return;
 
-
 	if (swptr < dmabuf->dmasize/2)
 		len = dmabuf->dmasize/2 - swptr;
 	else
@@ -979,7 +952,7 @@
 
 	memset(dmabuf->rawbuf + swptr, silence, len);
 
-	spin_lock_irqsave(&state->card->lock, flags);	
+	spin_lock_irqsave(&state->card->lock, flags);
 	dmabuf->swptr += len;
 	dmabuf->count += len;
 	spin_unlock_irqrestore(&state->card->lock, flags);
@@ -991,7 +964,7 @@
 static int drain_dac(struct trident_state *state, int nonblock)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	unsigned long tmo;
 	int count;
@@ -1038,49 +1011,49 @@
 	return 0;
 }
 
-/* call with spinlock held! */
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
 static void trident_update_ptr(struct trident_state *state)
 {
-	struct dmabuf *dmabuf;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned hwptr;
 	int diff;
 
-	/* update ADC pointer */
-	if (state->dma_adc.ready) {
-		dmabuf = &state->dma_adc;
-		hwptr = trident_get_dma_addr(state, 1);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-
-		dmabuf->hwptr = hwptr;
-		dmabuf->total_bytes += diff;
-		dmabuf->count += diff;
+	/* update hardware pointer */
+	hwptr = trident_get_dma_addr(state);
+	diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+	dmabuf->hwptr = hwptr;
+	dmabuf->total_bytes += diff;
 
-		if (dmabuf->count >= (signed)dmabuf->fragsize)
-			wake_up(&dmabuf->wait);
-		if (!dmabuf->mapped) {
-			if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) {
-				__stop_adc(state); 
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == ADC_RUNNING) {
+		if (dmabuf->mapped) {
+			dmabuf->count -= diff;
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			dmabuf->count += diff;
+
+			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+				/* buffer underrun or buffer overrun, we have no way to recover
+				   it here, just stop the machine and let the process force hwptr
+				   and swptr to sync */
+				__stop_adc(state);
 				dmabuf->error++;
 			}
+			/* since dma machine only interrupts at ESO and ESO/2, we sure have at
+			   least half of dma buffer free, so wake up the process unconditionally */
+			wake_up(&dmabuf->wait);
 		}
 	}
-
-	/* update DAC pointer */
-	if (state->dma_dac.ready) {
-		dmabuf = &state->dma_dac;
-		hwptr = trident_get_dma_addr(state, 0);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-
-		dmabuf->hwptr = hwptr;
-		dmabuf->total_bytes += diff;
-
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == DAC_RUNNING) {
 		if (dmabuf->mapped) {
 			dmabuf->count += diff;
-			if (dmabuf->count >= (signed)dmabuf->fragsize) 
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
 				wake_up(&dmabuf->wait);
-		}
-		else {
+		} else {
 			dmabuf->count -= diff;
+
 			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
 				/* buffer underrun or buffer overrun, we have no way to recover
 				   it here, just stop the machine and let the process force hwptr
@@ -1088,7 +1061,7 @@
 				__stop_dac(state);
 				dmabuf->error++;
 			}
-			/* since dma machine only interrupts at ESO and ESO/2, we sure have at 
+			/* since dma machine only interrupts at ESO and ESO/2, we sure have at
 			   least half of dma buffer free, so wake up the process unconditionally */
 			wake_up(&dmabuf->wait);
 		}
@@ -1120,17 +1093,13 @@
 				} else {
 					printk("trident: spurious channel irq %d.\n",
 					       63 - i);
-					trident_stop_voice(card, i);
-					trident_disable_voice_irq(card, i);	
+					trident_stop_voice(card, 63 - i);
+					trident_disable_voice_irq(card, 63 - i);
 				}
 			}
 		}
 	}
 
-	if (event & SB_IRQ){
-		/* Midi - TODO */
-	}
-
 	/* manually clear interrupt status, bad hardware design, blame T^2 */
 	outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
 	     TRID_REG(card, T4D_MISCINT));
@@ -1142,18 +1111,21 @@
 	return -ESPIPE;
 }
 
-/* in this loop, dma_adc.count signifies the amount of data thats waiting
-   to be copied to the user's buffer.  it is filled by the interrupt
-   handler and drained by this loop. */
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
+   the user's buffer.  it is filled by the dma machine and drained by this loop. */
 static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
 	int cnt;
 
+#ifdef DEBUG
+	printk("trident: trident_read called, count = %d\n", count);
+#endif
+
 	VALIDATE_STATE(state);
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -1167,6 +1139,12 @@
 
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->count > (signed) dmabuf->dmasize) {
+			/* buffer overrun, we are recovering from sleep_on_timeout,
+			   resync hwptr and swptr, make process flush the buffer */
+			dmabuf->count = dmabuf->dmasize;
+			dmabuf->swptr = dmabuf->hwptr;
+		}
 		swptr = dmabuf->swptr;
 		cnt = dmabuf->dmasize - swptr;
 		if (dmabuf->count < cnt)
@@ -1175,25 +1153,35 @@
 
 		if (cnt > count)
 			cnt = count;
-
 		if (cnt <= 0) {
+			unsigned long tmo;
+			/* buffer is empty, start the dma machine and wait for data to be
+			   recorded */
 			start_adc(state);
 			if (file->f_flags & O_NONBLOCK) {
-				ret = ret ? ret : -EAGAIN;
+				if (!ret) ret = -EAGAIN;
 				return ret;
 			}
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) {
-				printk(KERN_ERR
-				       "(trident) read: chip lockup? "
+			/* No matter how much space left in the buffer, we have to wait untill
+			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+			tmo >>= sample_shift[dmabuf->fmt];
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer overrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+				printk(KERN_ERR "trident: recording schedule timeout, "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
 				       dmabuf->hwptr, dmabuf->swptr);
-				stop_adc(state);
-				spin_lock_irqsave(&state->card->lock, flags);
-				dmabuf->count = 0;
-				dmabuf->hwptr = 0;
-				dmabuf->swptr = 0;
-				spin_unlock_irqrestore(&state->card->lock, flags);
+#endif
+				/* a buffer overrun, we delay the recovery untill next time the
+				   while loop begin and we REALLY have space to record */
 			}
 			if (signal_pending(current)) {
 				ret = ret ? ret : -ERESTARTSYS;
@@ -1203,7 +1191,7 @@
 		}
 
 		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-			ret = ret ? ret : -EFAULT;
+			if (!ret) ret = -EFAULT;
 			return ret;
 		}
 
@@ -1219,14 +1207,15 @@
 		ret += cnt;
 		start_adc(state);
 	}
-
 	return ret;
 }
 
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+   the soundcard.  it is drained by the dma machine and filled by this loop. */
 static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
-	struct dmabuf *dmabuf = &state->dma_dac;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
@@ -1234,7 +1223,7 @@
 
 #ifdef DEBUG
 	printk("trident: trident_write called, count = %d\n", count);
-#endif	
+#endif
 
 	VALIDATE_STATE(state);
 	if (ppos != &file->f_pos)
@@ -1265,7 +1254,8 @@
 			cnt = count;
 		if (cnt <= 0) {
 			unsigned long tmo;
-			/* buffer is full, start the dma machine and wait for data to be played */
+			/* buffer is full, start the dma machine and wait for data to be
+			   played */
 			start_dac(state);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
@@ -1275,15 +1265,16 @@
 			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
 			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
 			tmo >>= sample_shift[dmabuf->fmt];
-			/* There are two situations when sleep_on_timeout returns, one is when the
-			   interrupt is serviced correctly and the process is waked up by ISR ON TIME.
-			   Another is when timeout is expired, which means that either interrupt is NOT
-			   serviced correctly (pending interrupt) or it is TOO LATE for the process to 
-			   be scheduled to run (scheduler latency) which results in a (potential) buffer
-			   underrun. And worse, there is NOTHING we can do to prevent it. */
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer underrun. And worse, there is
+			   NOTHING we can do to prevent it. */
 			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
 #ifdef DEBUG
-				printk(KERN_ERR "trident: schedule timeout, "
+				printk(KERN_ERR "trident: playback schedule timeout, "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
 				       dmabuf->hwptr, dmabuf->swptr);
@@ -1307,7 +1298,6 @@
 		spin_lock_irqsave(&state->card->lock, flags);
 		dmabuf->swptr = swptr;
 		dmabuf->count += cnt;
-		dmabuf->endcleared = 0;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		count -= cnt;
@@ -1320,32 +1310,33 @@
 
 static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait)
 {
-	struct trident_state *s = (struct trident_state *)file->private_data;
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	unsigned int mask = 0;
 
-	VALIDATE_STATE(s);
+	VALIDATE_STATE(state);
 	if (file->f_mode & FMODE_WRITE)
-		poll_wait(file, &s->dma_dac.wait, wait);
+		poll_wait(file, &dmabuf->wait, wait);
 	if (file->f_mode & FMODE_READ)
-		poll_wait(file, &s->dma_adc.wait, wait);
+		poll_wait(file, &dmabuf->wait, wait);
 
-	spin_lock_irqsave(&s->card->lock, flags);
-	trident_update_ptr(s);
+	spin_lock_irqsave(&state->card->lock, flags);
+	trident_update_ptr(state);
 	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+		if (dmabuf->count >= (signed)dmabuf->fragsize)
 			mask |= POLLIN | POLLRDNORM;
 	}
 	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
+		if (dmabuf->mapped) {
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		} else {
-			if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		}
 	}
-	spin_unlock_irqrestore(&s->card->lock, flags);
+	spin_unlock_irqrestore(&state->card->lock, flags);
 
 	return mask;
 }
@@ -1353,7 +1344,7 @@
 static int trident_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
-	struct dmabuf *dmabuf;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	int ret;
 	unsigned long size;
 
@@ -1361,11 +1352,9 @@
 	if (vma->vm_flags & VM_WRITE) {
 		if ((ret = prog_dmabuf(state, 0)) != 0)
 			return ret;
-		dmabuf = &state->dma_dac;
 	} else if (vma->vm_flags & VM_READ) {
 		if ((ret = prog_dmabuf(state, 1)) != 0)
 			return ret;
-		dmabuf = &state->dma_adc;
 	} else 
 		return -EINVAL;
 
@@ -1385,14 +1374,15 @@
 static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	audio_buf_info abinfo;
 	count_info cinfo;
 	int val, mapped, ret;
 
 	VALIDATE_STATE(state);
-	mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && state->dma_adc.mapped);
+	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
+		((file->f_mode & FMODE_READ) && dmabuf->mapped);
 #ifdef DEBUG
 	printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
 	       _IOC_NR(cmd), arg ? *(int *)arg : 0);
@@ -1404,19 +1394,20 @@
 		return put_user(SOUND_VERSION, (int *)arg);
 
 	case SNDCTL_DSP_RESET:
+		/* FIXME: spin_lock ? */
 		if (file->f_mode & FMODE_WRITE) {
 			stop_dac(state);
 			synchronize_irq();
-			state->dma_dac.ready = 0;
-			state->dma_dac.swptr = state->dma_dac.hwptr = 0;
-			state->dma_dac.count = state->dma_dac.total_bytes = 0;
+			dmabuf->ready = 0;
+			dmabuf->swptr = dmabuf->hwptr = 0;
+			dmabuf->count = dmabuf->total_bytes = 0;
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(state);
 			synchronize_irq();
-			state->dma_adc.ready = 0;
-			state->dma_adc.swptr = state->dma_adc.hwptr = 0;
-			state->dma_adc.count = state->dma_adc.total_bytes = 0;
+			dmabuf->ready = 0;
+			dmabuf->swptr = dmabuf->hwptr = 0;
+			dmabuf->count = dmabuf->total_bytes = 0;
 		}
 		return 0;
 
@@ -1430,40 +1421,38 @@
 		if (val >= 0) {
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(state);
-				state->dma_dac.ready = 0;
+				dmabuf->ready = 0;
 				spin_lock_irqsave(&state->card->lock, flags);
 				trident_set_dac_rate(state, val);
 				spin_unlock_irqrestore(&state->card->lock, flags);
 			}
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(state);
-				state->dma_adc.ready = 0;
+				dmabuf->ready = 0;
 				spin_lock_irqsave(&state->card->lock, flags);
 				trident_set_adc_rate(state, val);
 				spin_unlock_irqrestore(&state->card->lock, flags);
 			}
 		}
-		return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
-				state->dma_dac.rate,
-				(int *)arg);
+		return put_user(dmabuf->rate, (int *)arg);
 
 	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (file->f_mode & FMODE_WRITE) {
 			stop_dac(state);
-			state->dma_dac.ready = 0;
+			dmabuf->ready = 0;
 			if (val)
-				state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
+				dmabuf->fmt |= TRIDENT_FMT_STEREO;
 			else
-				state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
+				dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(state);
-			state->dma_adc.ready = 0;
+			dmabuf->ready = 0;
 			if (val)
-				state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
+				dmabuf->fmt |= TRIDENT_FMT_STEREO;
 			else
-				state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
+				dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
 		}
 		return 0;
 
@@ -1471,12 +1460,12 @@
 		if (file->f_mode & FMODE_WRITE) {
 			if ((val = prog_dmabuf(state, 0)))
 				return val;
-			return put_user(state->dma_dac.fragsize, (int *)arg);
+			return put_user(dmabuf->fragsize, (int *)arg);
 		}
 		if (file->f_mode & FMODE_READ) {
 			if ((val = prog_dmabuf(state, 1)))
 				return val;
-			return put_user(state->dma_adc.fragsize, (int *)arg);
+			return put_user(dmabuf->fragsize, (int *)arg);
 		}
 
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
@@ -1487,120 +1476,99 @@
 		if (val != AFMT_QUERY) {
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(state);
-				state->dma_dac.ready = 0;
+				dmabuf->ready = 0;
 				if (val == AFMT_S16_LE)
-					state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
+					dmabuf->fmt |= TRIDENT_FMT_16BIT;
 				else
-					state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT;
+					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
 			}
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(state);
-				state->dma_adc.ready = 0;
+				dmabuf->ready = 0;
 				if (val == AFMT_S16_LE)
-					state->dma_adc.fmt |= TRIDENT_FMT_16BIT;
+					dmabuf->fmt |= TRIDENT_FMT_16BIT;
 				else
-					state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT;
+					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
 			}
 		}
-		if (file->f_mode & FMODE_WRITE)
-			return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
-					AFMT_S16_LE : AFMT_U8, (int *)arg);
-		else
-			return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
-					AFMT_S16_LE : AFMT_U8, (int *)arg);
+		return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
+				AFMT_S16_LE : AFMT_U8, (int *)arg);
 
 	case SNDCTL_DSP_CHANNELS:
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val != 0) {
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(state);
-				state->dma_dac.ready = 0;
+				dmabuf->ready = 0;
 				if (val >= 2)
-					state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
+					dmabuf->fmt |= TRIDENT_FMT_STEREO;
 				else
-					state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
+					dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
 			}
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(state);
-				state->dma_adc.ready = 0;
+				dmabuf->ready = 0;
 				if (val >= 2)
-					state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
+					dmabuf->fmt |= TRIDENT_FMT_STEREO;
 				else
-					state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
+					dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
 			}
 		}
-		if (file->f_mode & FMODE_WRITE)
-			return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-					(int *)arg);
-		else
-			return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-					(int *)arg);
+		return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+				(int *)arg);
+
 	case SNDCTL_DSP_POST:
 		/* FIXME: the same as RESET ?? */
 		return 0;
 
 	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision))
+		if (dmabuf->subdivision)
 			return -EINVAL;
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			state->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			state->dma_dac.subdivision = val;
+		dmabuf->subdivision = val;
 		return 0;
 
 	case SNDCTL_DSP_SETFRAGMENT:
 		get_user_ret(val, (int *)arg, -EFAULT);
-		if (file->f_mode & FMODE_READ) {
-			state->dma_adc.ossfragshift = val & 0xffff;
-			state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (state->dma_adc.ossfragshift < 4)
-				state->dma_adc.ossfragshift = 4;
-			if (state->dma_adc.ossfragshift > 15)
-				state->dma_adc.ossfragshift = 15;
-			if (state->dma_adc.ossmaxfrags < 4)
-				state->dma_adc.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			state->dma_dac.ossfragshift = val & 0xffff;
-			state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (state->dma_dac.ossfragshift < 4)
-				state->dma_dac.ossfragshift = 4;
-			if (state->dma_dac.ossfragshift > 15)
-				state->dma_dac.ossfragshift = 15;
-			if (state->dma_dac.ossmaxfrags < 4)
-				state->dma_dac.ossmaxfrags = 4;
-		}
+
+		dmabuf->ossfragshift = val & 0xffff;
+		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+		if (dmabuf->ossfragshift < 4)
+			dmabuf->ossfragshift = 4;
+		if (dmabuf->ossfragshift > 15)
+			dmabuf->ossfragshift = 15;
+		if (dmabuf->ossmaxfrags < 4)
+			dmabuf->ossmaxfrags = 4;
+
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0)
+		if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
 		trident_update_ptr(state);
-		abinfo.fragsize = state->dma_dac.fragsize;
-		abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count;
-		abinfo.fragstotal = state->dma_dac.numfrag;
-		abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift;      
+		abinfo.fragsize = dmabuf->fragsize;
+		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.fragstotal = dmabuf->numfrag;
+		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0)
+		if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
 		trident_update_ptr(state);
-		abinfo.fragsize = state->dma_adc.fragsize;
-		abinfo.bytes = state->dma_adc.count;
-		abinfo.fragstotal = state->dma_adc.numfrag;
-		abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift;      
+		abinfo.fragsize = dmabuf->fragsize;
+		abinfo.bytes = dmabuf->count;
+		abinfo.fragstotal = dmabuf->numfrag;
+		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
@@ -1609,14 +1577,13 @@
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
-	    return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
-			    (int *)arg);
+	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg);
 
 	case SNDCTL_DSP_GETTRIGGER:
 		val = 0;
-		if (file->f_mode & FMODE_READ && state->dma_adc.enable) 
+		if (file->f_mode & FMODE_READ && dmabuf->enable)
 			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && state->dma_dac.enable) 
+		if (file->f_mode & FMODE_WRITE && dmabuf->enable)
 			val |= PCM_ENABLE_OUTPUT;
 		return put_user(val, (int *)arg);
 
@@ -1624,20 +1591,18 @@
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
-				if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
+				if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 					return ret;
 				start_adc(state);
-			} 
-			else
+			} else
 				stop_adc(state);
 		}
 		if (file->f_mode & FMODE_WRITE) {
 			if (val & PCM_ENABLE_OUTPUT) {
-				if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
+				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 					return ret;
 				start_dac(state);
-			} 
-			else
+			} else
 				stop_dac(state);
 		}
 		return 0;
@@ -1647,59 +1612,50 @@
 			return -EINVAL;
 		spin_lock_irqsave(&state->card->lock, flags);
 		trident_update_ptr(state);
-		cinfo.bytes = state->dma_adc.total_bytes;
-		cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift;
-		cinfo.ptr = state->dma_adc.hwptr;
-		if (state->dma_adc.mapped)
-			state->dma_adc.count &= state->dma_adc.fragsize-1;
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped)
+			dmabuf->count &= dmabuf->fragsize-1;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-		
+
 	case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		spin_lock_irqsave(&state->card->lock, flags);
 		trident_update_ptr(state);
-		cinfo.bytes = state->dma_dac.total_bytes;
-		cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift;
-		cinfo.ptr = state->dma_dac.hwptr;
-		if (state->dma_dac.mapped)
-			state->dma_dac.count &= state->dma_dac.fragsize-1;
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped)
+			dmabuf->count &= dmabuf->fragsize-1;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
 	case SNDCTL_DSP_SETDUPLEX:
-		/* XXX fix */
-		return 0;
+		return -EINVAL;
 
 	case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		spin_lock_irqsave(&state->card->lock, flags);
 		trident_update_ptr(state);
-		val = state->dma_dac.count;
+		val = dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 		return put_user(val, (int *)arg);
 
 	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
-				state->dma_dac.rate, (int *)arg);
+		return put_user(dmabuf->rate, (int *)arg);
 
 	case SOUND_PCM_READ_CHANNELS:
-		if (file->f_mode & FMODE_WRITE)
-			return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-					(int *)arg);
-		else
-			return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
-					(int *)arg);
-		
+		return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+				(int *)arg);
+
 	case SOUND_PCM_READ_BITS:
-		if (file->f_mode & FMODE_WRITE)
-			return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
-					AFMT_S16_LE : AFMT_U8, (int *)arg);
-		else
-			return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
-					AFMT_S16_LE : AFMT_U8, (int *)arg);
+		return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
+				AFMT_S16_LE : AFMT_U8, (int *)arg);
+
 	case SNDCTL_DSP_MAPINBUF:
 	case SNDCTL_DSP_MAPOUTBUF:
 	case SNDCTL_DSP_SETSYNCRO:
@@ -1738,70 +1694,61 @@
 
  found_virt:
 	/* found a free virtual channel, allocate hardware channels */
-	if (file->f_mode & FMODE_READ)
-		if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) {
-			kfree (card->states[i]);
-			card->states[i] = NULL;;
-			return -ENODEV;
-		}
-	if (file->f_mode & FMODE_WRITE)
-		if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) {
-			kfree (card->states[i]);
-			card->states[i] = NULL;
-			if (file->f_mode & FMODE_READ)
-				/* free previously allocated hardware channel */
-				trident_free_pcm_channel(card, state->dma_adc.channel->num);
-			return -ENODEV;
-		}
+	if ((state->dmabuf.channel = trident_alloc_pcm_channel(card)) == NULL) {
+		kfree (card->states[i]);
+		card->states[i] = NULL;;
+		return -ENODEV;
+	}
 
 	/* initialize the virtual channel */
 	state->virt = i;
 	state->card = card;
 	state->magic = TRIDENT_STATE_MAGIC;
-	init_waitqueue_head(&state->dma_adc.wait);
-	init_waitqueue_head(&state->dma_dac.wait);
+	init_waitqueue_head(&state->dmabuf.wait);
 	init_MUTEX(&state->open_sem);
 	file->private_data = state;
 
 	down(&state->open_sem);
 
-	/* set default sample format, Refer to  OSS Programmer's Guide */
-	if (file->f_mode & FMODE_READ) {
-		/* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */
-		state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT;
-		state->dma_adc.ossfragshift = 0;
-		state->dma_adc.ossmaxfrags  = 0;
-		state->dma_adc.subdivision  = 0;
-		trident_set_adc_rate(state, 48000);
-	}
-
-	/* according to OSS document, /dev/dsp should be default to unsigned 8-bits, 
-	   mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */
+	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
+	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+	   /dev/dspW will accept 16-bits sample */
 	if (file->f_mode & FMODE_WRITE) {
-		state->dma_dac.fmt &= ~TRIDENT_FMT_MASK;
+		state->dmabuf.fmt &= ~TRIDENT_FMT_MASK;
 		if ((minor & 0xf) == SND_DEV_DSP16)
-			 state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
-		state->dma_dac.ossfragshift = 0;
-		state->dma_dac.ossmaxfrags  = 0;
-		state->dma_dac.subdivision  = 0;
+			state->dmabuf.fmt |= TRIDENT_FMT_16BIT;
+		state->dmabuf.ossfragshift = 0;
+		state->dmabuf.ossmaxfrags  = 0;
+		state->dmabuf.subdivision  = 0;
 		trident_set_dac_rate(state, 8000);
 	}
 
+	if (file->f_mode & FMODE_READ) {
+		/* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample,
+		   to be dealed with in trident_set_adc_rate() ?? */
+		state->dmabuf.fmt &= ~TRIDENT_FMT_MASK;
+		if ((minor & 0xf) == SND_DEV_DSP16)
+			state->dmabuf.fmt |= TRIDENT_FMT_16BIT;
+		state->dmabuf.ossfragshift = 0;
+		state->dmabuf.ossmaxfrags  = 0;
+		state->dmabuf.subdivision  = 0;
+		trident_set_adc_rate(state, 8000);
+	}
+
 	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&state->open_sem);
 
-	//FIXME put back in
-	//MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int trident_release(struct inode *inode, struct file *file)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
 
 	VALIDATE_STATE(state);
 
-
 	if (file->f_mode & FMODE_WRITE) {
 		trident_clear_tail(state);
 		drain_dac(state, file->f_flags & O_NONBLOCK);
@@ -1812,13 +1759,13 @@
 
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(state);
-		dealloc_dmabuf(&state->dma_dac);
-		trident_free_pcm_channel(state->card, state->dma_dac.channel->num);
+		dealloc_dmabuf(state);
+		trident_free_pcm_channel(state->card, dmabuf->channel->num);
 	}
 	if (file->f_mode & FMODE_READ) {
 		stop_adc(state);
-		dealloc_dmabuf(&state->dma_adc);
-		trident_free_pcm_channel(state->card, state->dma_adc.channel->num);
+		dealloc_dmabuf(state);
+		trident_free_pcm_channel(state->card, dmabuf->channel->num);
 	}
 
 	kfree(state->card->states[state->virt]);
@@ -1828,8 +1775,7 @@
 	/* we're covered by the open_sem */
 	up(&state->open_sem);
 
-	//FIXME put back in
-	//MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1845,7 +1791,7 @@
 };
 
 /* trident specific AC97 functions */
-/* Write AC97 mixer registers */
+/* Write AC97 codec registers */
 static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
 {
 	struct trident_card *card = (struct trident_card *)codec->private_data;
@@ -1863,7 +1809,7 @@
 		address = SI_AC97_WRITE;
 		mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
 		if (codec->id)
-		    mask |= SI_AC97_SECONDARY;
+			mask |= SI_AC97_SECONDARY;
 		busy = SI_AC97_BUSY_WRITE;
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
@@ -1874,7 +1820,7 @@
 		address = NX_ACR1_AC97_W;
 		mask = NX_AC97_BUSY_WRITE;
 		if (codec->id)
-		    mask |= NX_AC97_WRITE_SECONDARY;
+			mask |= NX_AC97_WRITE_SECONDARY;
 		busy = NX_AC97_BUSY_WRITE;
 		break;
 	}
@@ -1968,17 +1914,13 @@
  match:
 	file->private_data = card->ac97_codec[i];
 
-	//FIXME put back in
-	//MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int trident_release_mixdev(struct inode *inode, struct file *file)
 {
-	//struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
-	//FIXME put back in
-	//MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -2061,36 +2003,35 @@
 }
 
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */
-static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
+   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+static int __devinit trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
-	u16 w;
 	unsigned long iobase;
 	struct trident_card *card;
 
-	iobase = pcidev->resource[0].start;
+	if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) {
+		printk(KERN_ERR "trident: architecture does not support"
+		       " 30bit PCI busmaster DMA\n");
+		return -1;
+	}
+
+	iobase = pci_dev->resource[0].start;
 	if (check_region(iobase, 256)) {
 		printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
 		       iobase);
-		return 0;
+		return -1;
 	}
 
-	/* just to be sure that IO space and bus master is on */
-	pci_set_master(pcidev);	
-	pci_read_config_word(pcidev, PCI_COMMAND, &w);
-	w |= PCI_COMMAND_IO|PCI_COMMAND_MASTER;
-	pci_write_config_word(pcidev, PCI_COMMAND, w);
-
 	if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "trident: out of memory\n");
-		return 0;
+		return -1;
 	}
 	memset(card, 0, sizeof(*card));
 
 	card->iobase = iobase;
-	card->pci_info = pci_info;
-	card->pci_id = pci_info->device;
-	card->irq = pcidev->irq;
+	card->pci_dev = pci_dev;
+	card->pci_id = pci_id->device;
+	card->irq = pci_dev->irq;
 	card->next = devs;
 	card->magic = TRIDENT_CARD_MAGIC;
 	card->banks[BANK_A].addresses = &bank_a_addrs;
@@ -2098,14 +2039,18 @@
 	card->banks[BANK_B].addresses = &bank_b_addrs;
 	card->banks[BANK_B].bitmap = 0UL;
 	spin_lock_init(&card->lock);
-	devs = card;	
+	devs = card;
+
+	pci_set_master(pci_dev);
+	pci_enable_device(pci_dev);
 
 	printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
-	       card->pci_info->name, card->iobase, card->irq);
+	       card_names[pci_id->driver_data], card->iobase, card->irq);
 
 	/* claim our iospace and irq */
-	request_region(card->iobase, 256, card->pci_info->name);
-	if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) {
+	request_region(card->iobase, 256, card_names[pci_id->driver_data]);
+	if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ,
+			card_names[pci_id->driver_data], card)) {
 		printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq);
 		release_region(card->iobase, 256);
 		kfree(card);
@@ -2117,7 +2062,7 @@
 		release_region(iobase, 256);
 		free_irq(card->irq, card);
 		kfree(card);
-		return 0;
+		return -1;
 	}
 	/* initilize AC97 codec and register /dev/mixer */
 	if (trident_ac97_init(card) <= 0) {
@@ -2125,68 +2070,66 @@
 		release_region(iobase, 256);
 		free_irq(card->irq, card);
 		kfree(card);
-		return 0;
+		return -1;
 	}
 	outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
 
+	pci_dev->driver_data = card;
+	pci_dev->dma_mask = TRIDENT_DMA_MASK;
+
 	/* Enable Address Engine Interrupts */
 	trident_enable_loop_interrupts(card);
 
-	return 1; 
+	return 0;
 }
 
-static int __init init_trident(void)
+static void __devexit trident_remove(struct pci_dev *pci_dev)
 {
-	struct pci_dev *pcidev = NULL;
-	int foundone = 0;
 	int i;
+	struct trident_card *card = pci_dev->driver_data;
 
-	if (!pci_present())   /* No PCI bus in this machine! */
-		return -ENODEV;
+	/* Kill interrupts, and SP/DIF */
+	trident_disable_loop_interrupts(card);
 
-	printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
-	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+	/* free hardware resources */
+	free_irq(card->irq, devs);
+	release_region(card->iobase, 256);
 
-	for (i = 0; i < sizeof (pci_audio_devices); i++) {
-		pcidev = NULL;
-		while ((pcidev = pci_find_device(pci_audio_devices[i].vendor,
-						 pci_audio_devices[i].device,
-						 pcidev)) != NULL) {
-			foundone += trident_install(pcidev, pci_audio_devices + i);
+	/* unregister audio devices */
+	for (i = 0; i < NR_AC97; i++)
+		if (devs->ac97_codec[i] != NULL) {
+			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
+			kfree (card->ac97_codec[i]);
 		}
-	}
+	unregister_sound_dsp(card->dev_audio);
 
-	if (!foundone)
-		return -ENODEV;
-	return 0;
+	kfree(card);
 }
 
 MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
 MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
 
-static void __exit cleanup_trident(void)
+#define TRIDENT_MODULE_NAME "trident"
+
+static struct pci_driver trident_pci_driver = {
+	name:		TRIDENT_MODULE_NAME,
+	id_table:	trident_pci_tbl,
+	probe:		trident_probe,
+	remove:		trident_remove,
+};
+
+static int __init trident_init_module (void)
 {
-	while (devs != NULL) {
-		int i;
-		/* Kill interrupts, and SP/DIF */
-		trident_disable_loop_interrupts(devs);
-
-		/* free hardware resources */
-		free_irq(devs->irq, devs);
-		release_region(devs->iobase, 256);
+	printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
-		/* unregister audio devices */
-		for (i = 0; i < NR_AC97; i++)
-			if (devs->ac97_codec[i] != NULL) {
-				unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer);
-				kfree (devs->ac97_codec[i]);
-			}
-		unregister_sound_dsp(devs->dev_audio);
+	return pci_module_init (&trident_pci_driver);
+}
 
-		kfree(devs);
-		devs = devs->next;
-	}
+static void __exit trident_cleanup_module (void)
+{
+	pci_unregister_driver (&trident_pci_driver);
 }
 
-module_init(init_trident);
-module_exit(cleanup_trident);
+module_init(trident_init_module);
+module_exit(trident_cleanup_module);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/trident.h linux/drivers/sound/trident.h
--- v2.3.49/linux/drivers/sound/trident.h	Tue Feb  1 01:35:44 2000
+++ linux/drivers/sound/trident.h	Thu Mar  2 22:44:07 2000
@@ -60,13 +60,13 @@
 #define TRIDENT_FMT_16BIT      0x02
 #define TRIDENT_FMT_MASK       0x03
 
-#define DMA_ENABLE	0x01
-#define DMA_RUNNING	0x02
-
+#define DAC_RUNNING	0x01
+#define ADC_RUNNING	0x02
 /* Register Addresses */
 
 /* operational registers common to DX, NX, 7018 */
 enum trident_op_registers {
+	T4D_REC_CH	= 0x70,
 	T4D_START_A     = 0x80, T4D_STOP_A      = 0x84,
 	T4D_DLY_A       = 0x88, T4D_SIGN_CSO_A  = 0x8c,
 	T4D_CSPF_A      = 0x90, T4D_CEBC_A      = 0x94,
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.3.49/linux/drivers/sound/trix.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/sound/trix.c	Tue Mar  7 13:40:24 2000
@@ -13,9 +13,11 @@
  *
  * Changes
  *	Alan Cox		Modularisation, cleanup.
+ *	Christoph Hellwig	Adapted to module_init/module_exit
  */
  
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
@@ -23,9 +25,10 @@
 #include "sb.h"
 #include "sound_firmware.h"
 
-#include <linux/init.h>
-#include "trix_boot.h"
+#include "ad1848.h"
+#include "mpu401.h"
 
+#include "trix_boot.h"
 
 static int kilroy_was_here = 0;	/* Don't detect twice */
 static int sb_initialized = 0;
@@ -35,11 +38,7 @@
 
 static int mpu = 0;
 
-#ifdef TRIX_JOYSTICK
-static int joystick=1;
-#else
 static int joystick=0;
-#endif
 
 static unsigned char trix_read(int addr)
 {
@@ -137,7 +136,7 @@
  *      AudioTrix Pro
  */
 
-int probe_trix_wss(struct address_info *hw_config)
+static int __init probe_trix_wss(struct address_info *hw_config)
 {
 	int ret;
 
@@ -202,8 +201,7 @@
 	return ret;
 }
 
-void
-attach_trix_wss(struct address_info *hw_config)
+static void __init attach_trix_wss(struct address_info *hw_config)
 {
 	static unsigned char interrupt_bits[12] = {
 		0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20
@@ -273,7 +271,7 @@
 	}
 }
 
-int probe_trix_sb(struct address_info *hw_config)
+static int __init probe_trix_sb(struct address_info *hw_config)
 {
 
 	int tmp;
@@ -323,7 +321,7 @@
 	return sb_dsp_detect(hw_config, 0, 0);
 }
 
-void attach_trix_sb(struct address_info *hw_config)
+static void __init attach_trix_sb(struct address_info *hw_config)
 {
 	extern int sb_be_quiet;
 	int old_quiet;
@@ -339,13 +337,13 @@
 	sb_be_quiet = old_quiet;
 }
 
-void attach_trix_mpu(struct address_info *hw_config)
+static void __init attach_trix_mpu(struct address_info *hw_config)
 {
 	hw_config->name = "AudioTrix Pro";
 	attach_uart401(hw_config);
 }
 
-int probe_trix_mpu(struct address_info *hw_config)
+static int __init probe_trix_mpu(struct address_info *hw_config)
 {
 	unsigned char conf;
 	static char irq_bits[] = {
@@ -406,7 +404,7 @@
 	return probe_uart401(hw_config);
 }
 
-void unload_trix_wss(struct address_info *hw_config)
+static void __exit unload_trix_wss(struct address_info *hw_config)
 {
 	int dma2 = hw_config->dma2;
 
@@ -424,31 +422,32 @@
 	sound_unload_audiodev(hw_config->slots[0]);
 }
 
-void unload_trix_mpu(struct address_info *hw_config)
+static inline void __exit unload_trix_mpu(struct address_info *hw_config)
 {
 	unload_uart401(hw_config);
 }
 
-void unload_trix_sb(struct address_info *hw_config)
+static inline void __exit unload_trix_sb(struct address_info *hw_config)
 {
 	sb_dsp_unload(hw_config, mpu);
 }
 
-#ifdef MODULE
-
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma2 = -1;	/* Set this for modules that need it */
-
-int             sb_io = -1;
-int             sb_dma = -1;
-int             sb_irq = -1;
-
-int             mpu_io = -1;
-int             mpu_irq = -1;
-
-EXPORT_NO_SYMBOLS;
+static struct address_info cfg;
+static struct address_info cfg2;
+static struct address_info cfg_mpu;
+
+static int sb = 0;
+static int fw_load;
+
+static int __initdata io	= -1;
+static int __initdata irq	= -1;
+static int __initdata dma	= -1;
+static int __initdata dma2	= -1;	/* Set this for modules that need it */
+static int __initdata sb_io	= -1;
+static int __initdata sb_dma	= -1;
+static int __initdata sb_irq	= -1;
+static int __initdata mpu_io	= -1;
+static int __initdata mpu_irq	= -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
@@ -460,42 +459,33 @@
 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;
-
-static int      sb = 0;
-
-static int      fw_load;
 
-int init_module(void)
+static int __init init_trix(void)
 {
 	printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
-	if (io == -1 || dma == -1 || irq == -1)
-	{
+	cfg.io_base = io;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.dma2 = dma2;
+
+	cfg2.io_base = sb_io;
+	cfg2.irq = sb_irq;
+	cfg2.dma = sb_dma;
+
+	cfg_mpu.io_base = mpu_io;
+	cfg_mpu.irq = mpu_irq;
+
+	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
 		printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n");
 		return -EINVAL;
 	}
-	config.io_base = io;
-	config.irq = irq;
-	config.dma = dma;
-	config.dma2 = dma2;
-
-	sb_config.io_base = sb_io;
-	sb_config.irq = sb_irq;
-	sb_config.dma = sb_dma;
 
-	mpu_config.io_base = mpu_io;
-	mpu_config.irq = mpu_irq;
-
-	if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1))
-	{
+	if (cfg2.io_base != -1 && (cfg2.irq == -1 || cfg2.dma == -1)) {
 		printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n");
 		return -EINVAL;
 	}
-	if (mpu_io != -1 && mpu_irq == -1)
-	{
+	if (cfg_mpu.io_base != -1 && cfg_mpu.irq == -1) {
 		printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n");
 		return -EINVAL;
 	}
@@ -505,42 +495,65 @@
 		trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin",
 						    (char **) &trix_boot);
 	}
-	if (!probe_trix_wss(&config))
+	if (!probe_trix_wss(&cfg))
 		return -ENODEV;
-	attach_trix_wss(&config);
+	attach_trix_wss(&cfg);
 
 	/*
 	 *    We must attach in the right order to get the firmware
 	 *      loaded up in time.
 	 */
 
-	if (sb_io != -1)
-	{
-		sb = probe_trix_sb(&sb_config);
+	if (cfg2.io_base != -1) {
+		sb = probe_trix_sb(&cfg2);
 		if (sb)
-			attach_trix_sb(&sb_config);
+			attach_trix_sb(&cfg2);
 	}
 	
-	if (mpu_io != -1)
-	{
-		mpu = probe_trix_mpu(&mpu_config);
+	if (cfg_mpu.io_base != -1) {
+		mpu = probe_trix_mpu(&cfg_mpu);
 		if (mpu)
-			attach_trix_mpu(&mpu_config);
+			attach_trix_mpu(&cfg_mpu);
 	}
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_trix(void)
 {
 	if (fw_load && trix_boot)
 		vfree(trix_boot);
 	if (sb)
-		unload_trix_sb(&sb_config);
+		unload_trix_sb(&cfg2);
 	if (mpu)
-		unload_trix_mpu(&mpu_config);
-	unload_trix_wss(&config);
+		unload_trix_mpu(&cfg_mpu);
+	unload_trix_wss(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_trix);
+module_exit(cleanup_trix);
+
+#ifndef MODULE
+static int __init setup_trix (char *str)
+{
+	/* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, mpu_io, mpu_irq */
+	int ints[9];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma2	= ints[4];
+	sb_io	= ints[5];
+	sb_irq	= ints[6];
+	sb_dma	= ints[6];
+	mpu_io	= ints[7];
+	mpu_irq	= ints[8];
+
+	return 1;
+}
+
+__setup("trix=", setup_trix);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c
--- v2.3.49/linux/drivers/sound/uart401.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/uart401.c	Tue Mar  7 13:40:24 2000
@@ -2,8 +2,8 @@
  * sound/uart401.c
  *
  * MPU-401 UART driver (formerly uart401_midi.c)
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -11,19 +11,23 @@
  * for more info.
  *
  * Changes:
- *	Alan Cox	Reformatted, removed sound_mem usage, use normal Linux
- *			interrupt allocation. Protect against bogus unload
- *			Fixed to allow IRQ > 15
+ *	Alan Cox		Reformatted, removed sound_mem usage, use normal Linux
+ *				interrupt allocation. Protect against bogus unload
+ *				Fixed to allow IRQ > 15
+ *	Christoph Hellwig	Adapted to module_init/module_exit
  *
  * Status:
  *		Untested
  */
- 
+
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 
+#include "mpu401.h"
+
 typedef struct uart401_devc
 {
 	int             base;
@@ -177,21 +181,21 @@
 	return 1;
 }
 
-static int uart401_start_read(int dev)
+static inline int uart401_start_read(int dev)
 {
 	return 0;
 }
 
-static int uart401_end_read(int dev)
+static inline int uart401_end_read(int dev)
 {
 	return 0;
 }
 
-static void uart401_kick(int dev)
+static inline void uart401_kick(int dev)
 {
 }
 
-static int uart401_buffer_status(int dev)
+static inline int uart401_buffer_status(int dev)
 {
 	return 0;
 }
@@ -444,43 +448,60 @@
 	sound_unload_mididev(hw_config->slots[4]);
 }
 
-#ifdef MODULE
+EXPORT_SYMBOL(attach_uart401);
+EXPORT_SYMBOL(probe_uart401);
+EXPORT_SYMBOL(unload_uart401);
+EXPORT_SYMBOL(uart401intr);
+
+static struct address_info cfg_mpu;
 
-int io = -1;
-int irq = -1;
+static int __initdata io = -1;
+static int __initdata irq = -1;
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
-struct address_info hw;
 
-int init_module(void)
+
+static int __init init_uart401(void)
 {
+	cfg_mpu.irq = irq;
+	cfg_mpu.io_base = io;
+
 	/* Can be loaded either for module use or to provide functions
 	   to others */
-	if (io != -1 && irq != -1)
-	{
+	if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) {
 		printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
-		hw.irq = irq;
-		hw.io_base = io;
-		if (probe_uart401(&hw) == 0)
+		if (probe_uart401(&cfg_mpu) == 0)
 			return -ENODEV;
-		attach_uart401(&hw);
+		attach_uart401(&cfg_mpu);
 	}
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_uart401(void)
 {
-	if (io != -1 && irq != -1)
-		unload_uart401(&hw);
-	/*  FREE SYMTAB */
+	if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1)
+		unload_uart401(&cfg_mpu);
 	SOUND_LOCK_END;
 }
 
-#endif /* MODULE */
+module_init(init_uart401);
+module_exit(cleanup_uart401);
 
-EXPORT_SYMBOL(attach_uart401);
-EXPORT_SYMBOL(probe_uart401);
-EXPORT_SYMBOL(unload_uart401);
-EXPORT_SYMBOL(uart401intr);
+#ifndef MODULE
+static int __init setup_uart401(char *str)
+{
+	/* io, irq */
+	int ints[3];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	io = ints[1];
+	irq = ints[2];
+	
+	return 1;
+}
+
+__setup("uart401=", setup_uart401);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v2.3.49/linux/drivers/sound/uart6850.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/uart6850.c	Tue Mar  7 13:40:24 2000
@@ -1,7 +1,7 @@
 /*
  * sound/uart6850.c
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -10,12 +10,15 @@
  * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver.
  * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2.
  *
- * Alan Cox:	Updated for new modular code. Removed snd_* irq handling. Now
- *		uses native linux resources
+ * Alan Cox:		Updated for new modular code. Removed snd_* irq handling. Now
+ *			uses native linux resources
+ * Christoph Hellwig:	Adapted to module_init/module_exit
  *
  *	Status: Testing required
  *
  */
+
+#include <linux/init.h>
 #include <linux/module.h>
 
 /* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl:
@@ -199,26 +202,26 @@
 	return 1;
 }
 
-static int uart6850_command(int dev, unsigned char *midi_byte)
+static inline int uart6850_command(int dev, unsigned char *midi_byte)
 {
 	return 1;
 }
 
-static int uart6850_start_read(int dev)
+static inline int uart6850_start_read(int dev)
 {
 	return 0;
 }
 
-static int uart6850_end_read(int dev)
+static inline int uart6850_end_read(int dev)
 {
 	return 0;
 }
 
-static void uart6850_kick(int dev)
+static inline void uart6850_kick(int dev)
 {
 }
 
-static int uart6850_buffer_status(int dev)
+static inline int uart6850_buffer_status(int dev)
 {
 	return 0;		/*
 				 * No data in buffers
@@ -246,7 +249,7 @@
 };
 
 
-void attach_uart6850(struct address_info *hw_config)
+static void __init attach_uart6850(struct address_info *hw_config)
 {
 	int ok, timeout;
 	unsigned long   flags;
@@ -292,7 +295,7 @@
 }
 
 
-int probe_uart6850(struct address_info *hw_config)
+static int __init probe_uart6850(struct address_info *hw_config)
 {
 	int ok = 0;
 
@@ -308,45 +311,58 @@
 	return ok;
 }
 
-void unload_uart6850(struct address_info *hw_config)
+static void __exit unload_uart6850(struct address_info *hw_config)
 {
 	free_irq(hw_config->irq, NULL);
 	sound_unload_mididev(hw_config->slots[4]);
 }
 
+static struct address_info cfg_mpu;
 
-#ifdef MODULE
-
-int io = -1;
-int irq = -1;
+static int __initdata io = -1;
+static int __initdata irq = -1;
 
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
 
-EXPORT_NO_SYMBOLS;
-
-struct address_info cfg;
-
-int init_module(void)
+static int __init init_uart6850(void)
 {
-	if (io == -1 || irq == -1)
-	{
+	cfg_mpu.io_base = io;
+	cfg_mpu.irq = irq;
+
+	if (cfg_mpu.io_base == -1 || cfg_mpu.irq == -1) {
 		printk(KERN_INFO "uart6850: irq and io must be set.\n");
 		return -EINVAL;
 	}
-	cfg.io_base = io;
-	cfg.irq = irq;
 
-	if (probe_uart6850(&cfg))
+	if (probe_uart6850(&cfg_mpu))
 		return -ENODEV;
 
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_uart6850(void)
 {
-	unload_uart6850(&cfg);
+	unload_uart6850(&cfg_mpu);
 	SOUND_LOCK_END;
 }
-#endif /* MODULE */
+
+module_init(init_uart6850);
+module_exit(cleanup_uart6850);
+
+#ifndef MODULE
+static int __init setup_uart6850(char *str)
+{
+	/* io, irq */
+	int ints[3];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io = ints[1];
+	irq = ints[2];
+
+	return 1;
+}
+__setup("uart6850=", setup_uart6850);
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/v_midi.c linux/drivers/sound/v_midi.c
--- v2.3.49/linux/drivers/sound/v_midi.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/v_midi.c	Tue Mar  7 13:40:24 2000
@@ -13,11 +13,13 @@
  *
  * Changes
  *	Alan Cox		Modularisation, changed memory allocations
+ *	Christoph Hellwig	Adapted to module_init/module_exit
  *
  * Status
  *	Untested
  */
 
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include "sound_config.h"
@@ -29,28 +31,6 @@
 static int midi1,midi2;
 static void *midi_mem = NULL;
 
-#ifdef MODULE
-
-static struct address_info config;	/* dummy */
-
-int init_module(void)
-{
-	printk("MIDI Loopback device driver\n");
-	if (!probe_v_midi(&config))
-		return -ENODEV;
-	attach_v_midi(&config);
-	SOUND_LOCK;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unload_v_midi(&config);
-	SOUND_LOCK_END;
-}
-
-#endif /* MODULE */
-
 /*
  * The DSP channel can be used either for input or output. Variable
  * 'sb_irq_mode' will be set when the program calls read or write first time
@@ -126,7 +106,7 @@
 	return 1;
 }
 
-static int v_midi_start_read (int dev)
+static inline int v_midi_start_read (int dev)
 {
 	return 0;
 }
@@ -143,7 +123,7 @@
 
 /* why -EPERM and not -EINVAL?? */
 
-static int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
+static inline int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
 	return -EPERM;
 }
@@ -201,7 +181,7 @@
 	struct vmidi_devc v_ops[2];
 };
 
-void attach_v_midi (struct address_info *hw_config)
+static void __init attach_v_midi (struct address_info *hw_config)
 {
 	struct vmidi_memory *m;
 	/* printk("Attaching v_midi device.....\n"); */
@@ -282,15 +262,38 @@
 	/* printk("Attached v_midi device\n"); */
 }
 
-int probe_v_midi(struct address_info *hw_config)
+static inline int __init probe_v_midi(struct address_info *hw_config)
 {
 	return(1);	/* always OK */
 }
 
 
-void unload_v_midi(struct address_info *hw_config)
+static void __exit unload_v_midi(struct address_info *hw_config)
 {
 	sound_unload_mididev(midi1);
 	sound_unload_mididev(midi2);
 	kfree(midi_mem);
 }
+
+static struct address_info cfg; /* dummy */
+
+static int __init init_vmidi(void)
+{
+	printk("MIDI Loopback device driver\n");
+	if (!probe_v_midi(&cfg))
+		return -ENODEV;
+	attach_v_midi(&cfg);
+
+	SOUND_LOCK;
+
+	return 0;
+}
+
+static void __exit cleanup_vmidi(void)
+{
+	unload_v_midi(&cfg);
+	SOUND_LOCK_END;
+}
+
+module_init(init_vmidi);
+module_exit(cleanup_vmidi);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.3.49/linux/drivers/sound/via82cxxx_audio.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/via82cxxx_audio.c	Tue Mar  7 13:40:24 2000
@@ -33,6 +33,7 @@
 #include "soundmodule.h"
 #include "sb.h"
 #include "ac97.h"
+#include "mpu401.h"
 
 #ifndef SOUND_LOCK
 #define SOUND_LOCK do {} while (0)
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c
--- v2.3.49/linux/drivers/sound/vidc.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/sound/vidc.c	Tue Mar  7 13:40:24 2000
@@ -14,6 +14,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 
@@ -412,7 +413,7 @@
 	}
 }
 
-void attach_vidc(struct address_info *hw_config)
+static void __init attach_vidc(struct address_info *hw_config)
 {
 	char name[32];
 	int i, adev;
@@ -486,7 +487,7 @@
 	return;
 }
 
-int probe_vidc(struct address_info *hw_config)
+static int __init probe_vidc(struct address_info *hw_config)
 {
 	hw_config->irq		= IRQ_DMAS0;
 	hw_config->dma		= DMA_VIRTUAL_SOUND;
@@ -496,7 +497,7 @@
 	return 1;
 }
 
-void unload_vidc(struct address_info *hw_config)
+static void __exit unload_vidc(struct address_info *hw_config)
 {
 	int i, adev = vidc_adev;
 
@@ -516,27 +517,27 @@
 	}
 }
 
-#ifdef MODULE
-static struct address_info config;
+static struct address_info cfg;
 /*
  * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END
  */
 
-int init_module(void)
+static int __init init_vidc(void)
 {
-	if (probe_vidc(&config) == 0)
+	if (probe_vidc(&cfg) == 0)
 		return -ENODEV;
 
 	SOUND_LOCK;
-	attach_vidc(&config);
+	attach_vidc(&cfg);
 
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_vidc(void)
 {
-	unload_vidc(&config);
+	unload_vidc(&cfg);
 	SOUND_LOCK_END;
 }
 
-#endif
+module_init(init_vidc);
+module_exit(cleanup_vidc);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c
--- v2.3.49/linux/drivers/sound/waveartist.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/sound/waveartist.c	Tue Mar  7 13:40:24 2000
@@ -6,9 +6,8 @@
  *
  * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk)
  * and Pat Beirne (patb@corel.ca)
- */
-
-/*
+ *
+ *
  * Copyright (C) by Rebel.com 1998-1999
  *
  * RWA010 specs received under NDA from Rockwell
@@ -31,6 +30,7 @@
 #define debug_flg (0)
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -1281,8 +1281,7 @@
 	return -1;
 }
 
-int
-probe_waveartist(struct address_info *hw_config)
+static int __init probe_waveartist(struct address_info *hw_config)
 {
 	wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
@@ -1316,8 +1315,7 @@
 	return 1;
 }
 
-void
-attach_waveartist(struct address_info *hw)
+static void __init attach_waveartist(struct address_info *hw)
 {
 	wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
@@ -1359,8 +1357,7 @@
 	}
 }
 
-void
-unload_waveartist(struct address_info *hw)
+static void __exit unload_waveartist(struct address_info *hw)
 {
 	wavnc_info *devc = NULL;
 	int i;
@@ -1757,45 +1754,63 @@
 	return -ENOIOCTLCMD;
 }
 
-#ifdef MODULE
+static struct address_info cfg;
+
+static int attached;
+
+static int __initdata io;
+static int __initdata irq;
+static int __initdata dma;
+static int __initdata dma2;
+
 
 MODULE_PARM(io, "i");		/* IO base */
 MODULE_PARM(irq, "i");		/* IRQ */
 MODULE_PARM(dma, "i");		/* DMA */
 MODULE_PARM(dma2, "i");		/* DMA2 */
 
-static int io   = CONFIG_WAVEARTIST_BASE;
-static int irq  = CONFIG_WAVEARTIST_IRQ;
-static int dma  = CONFIG_WAVEARTIST_DMA;
-static int dma2 = CONFIG_WAVEARTIST_DMA2;
-
-static int attached;
-
-static struct address_info hw_config;
-
-int init_module(void)
+static int __init init_waveartist(void)
 {
-	hw_config.io_base = io;
-	hw_config.irq = irq;
-	hw_config.dma = dma;
-	hw_config.dma2 = dma2;
+	cfg.io_base = io;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.dma2 = dma2;
 
-	if (!probe_waveartist(&hw_config))
+	if (!probe_waveartist(&cfg))
 		return -ENODEV;
 
-	attach_waveartist(&hw_config);
+	attach_waveartist(&cfg);
 	attached = 1;
 
 	SOUND_LOCK;
 	return 0;
 }
 
-void cleanup_module(void)
+static void __exit cleanup_waveartist(void)
 {
 	if (attached) {
 		SOUND_LOCK_END;
-
-		unload_waveartist(&hw_config);
+		unload_waveartist(&cfg);
 	}
 }
+
+module_init(init_waveartist);
+module_exit(cleanup_waveartist);
+
+#ifndef MODULE
+static int __init setup_waveartist(char *str)
+{
+	/* io, irq, dma, dma2 */
+	int ints[5];
+	
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	
+	io	= ints[1];
+	irq	= ints[2];
+	dma	= ints[3];
+	dma16	= ints[4];
+
+	return 1;
+}
+__setup("waveartist=", setup_waveartist);
 #endif
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c
--- v2.3.49/linux/drivers/sound/wavfront.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/sound/wavfront.c	Tue Mar  7 13:40:24 2000
@@ -65,6 +65,7 @@
 #include <linux/module.h>
 
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/fcntl.h>
@@ -128,10 +129,6 @@
 			       int offs, int count, int pmgr_flag) = NULL;
 #endif OSS_SUPPORT_SEQ
 
-/* This is meant to work as a module */
-
-#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE)
-
 /* if WF_DEBUG not defined, no run-time debugging messages will
    be available via the debug flag setting. Given the current
    beta state of the driver, this will remain set until a future 
@@ -2144,25 +2141,23 @@
 
 #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL
 
-void attach_wavefront (struct address_info *hw_config)
-
+static void __init attach_wavefront (struct address_info *hw_config)
 {
     (void) install_wavefront ();
 }
 
-int probe_wavefront (struct address_info *hw_config)
-
+static int __init probe_wavefront (struct address_info *hw_config)
 {
     return !detect_wavefront (hw_config->irq, hw_config->io_base);
 }
 
-void unload_wavefront (struct address_info *hw_config) 
+static void __exit unload_wavefront (struct address_info *hw_config) 
 {
     (void) uninstall_wavefront ();
 }
 
 #endif OSS_SUPPORT_STATIC_INSTALL
-
+
 /***********************************************************************/
 /* WaveFront: Linux modular sound kernel installation interface        */
 /***********************************************************************/
@@ -2814,8 +2809,7 @@
 	return 1;
 }
 
-static int
-wavefront_init (int atboot)
+static int __init wavefront_init (int atboot)
 {
 	int samples_are_from_rom;
 
@@ -2884,9 +2878,7 @@
 	return dev.oss_dev;
 }
 
-void
-uninstall_wavefront (void)
-
+static void __exit uninstall_wavefront (void)
 {
 	/* the first two i/o addresses are freed by the wf_mpu code */
 	release_region (dev.base+2, 6);
@@ -2938,7 +2930,7 @@
 	return (1);
 }
 
-static int __init detect_wffx (void)
+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
@@ -2954,7 +2946,7 @@
 	return 0;
 }	
 
-static int __init attach_wffx (void)
+int __init attach_wffx (void)
 {
 	if ((dev.fx_mididev = sound_alloc_mididev ()) < 0) {
 		printk (KERN_WARNING LOGNAME "cannot install FX Midi driver\n");
@@ -2964,7 +2956,7 @@
 	return 0;
 }
 
-static void
+void
 wffx_mute (int onoff)
     
 {
@@ -3087,9 +3079,7 @@
    a somewhat "algorithmic" approach.
 */
 
-static int
-wffx_init (void)
-
+static int wffx_init (void)
 {
 	int i;
 	int j;
@@ -3543,18 +3533,15 @@
 	return (0);
 }
 
-EXPORT_NO_SYMBOLS;
-
-int io = -1;
-int irq = -1;
+static int io = -1;
+static int irq = -1;
 
 MODULE_AUTHOR      ("Paul Barton-Davis <pbd@op.net>");
 MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver");
 MODULE_PARM        (io,"i");
 MODULE_PARM        (irq,"i");
 
-int init_module (void)
-
+static int __init init_wavfront (void)
 {
 	printk ("Turtle Beach WaveFront Driver\n"
 		"Copyright (C) by Hannu Solvainen, "
@@ -3585,14 +3572,11 @@
 	return 0;
 }
 
-void cleanup_module (void)
-
+static void __exit cleanup_wavfront (void)
 {
 	uninstall_wavefront ();
-
 	SOUND_LOCK_END;
 }
 
-#endif CONFIG_SOUND_WAVEFRONT_MODULE && MODULE
-
-
+module_init(init_wavfront);
+module_exit(cleanup_wavfront);
diff -u --recursive --new-file v2.3.49/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c
--- v2.3.49/linux/drivers/sound/wf_midi.c	Mon Jul  5 19:58:25 1999
+++ linux/drivers/sound/wf_midi.c	Tue Mar  7 13:40:24 2000
@@ -42,7 +42,7 @@
  * Copyright (C) by Paul Barton-Davis 1998
  * Some portions of this file are derived from work that is:
  *
- *    Copyright (C) by Hannu Savolainen 1993-1996
+ *    CopyriGht (C) by Hannu Savolainen 1993-1996
  *
  * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
@@ -56,7 +56,7 @@
 
 #include <linux/wavefront.h>
 
-#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE)
+#ifdef MODULE
 
 struct wf_mpu_config {
 	int             base;
@@ -87,37 +87,27 @@
 #define	MPU_ACK		0xFE
 #define	UART_MODE_ON	0x3F
 
-static inline int 
-wf_mpu_status (void)
-
+static inline int wf_mpu_status (void)
 {
 	return inb (STATPORT (phys_dev));
 }
 
-static inline int 
-input_avail (void)
-
+static inline int input_avail (void)
 {
 	return !(wf_mpu_status() & INPUT_AVAIL);
 }
 
-static inline int
-output_ready (void)
-
+static inline int output_ready (void)
 {
 	return !(wf_mpu_status() & OUTPUT_READY);
 }
 
-static inline int 
-read_data (void)
-
+static inline int  read_data (void)
 {
 	return inb (DATAPORT (phys_dev));
 }
 
-static inline void 
-write_data (unsigned char byte)
-
+static inline void write_data (unsigned char byte)
 {
 	outb (byte, DATAPORT (phys_dev));
 }
@@ -536,28 +526,22 @@
 	return 1;
 }
 
-static int
-wf_mpu_start_read (int dev)
-{
+static inline int wf_mpu_start_read (int dev) {
 	return 0;
 }
 
-static int
-wf_mpu_end_read (int dev)
-{
+static inline int wf_mpu_end_read (int dev) {
 	return 0;
 }
 
-static int
-wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg)
+static int wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
 	printk (KERN_WARNING
 		"WF-MPU: Intelligent mode not supported by hardware.\n");
 	return -(EINVAL);
 }
 
-static int
-wf_mpu_buffer_status (int dev)
+static int wf_mpu_buffer_status (int dev)
 {
 	return 0;
 }
@@ -901,31 +885,4 @@
 
 	restore_flags (flags);
 }
-
-#ifdef OSS_SUPPORT
-
-int
-probe_wf_mpu (struct address_info *hw_config)
-
-{
-	return !detect_wf_mpu (hw_config->irq, hw_config->io_base);
-}
-
-void
-attach_wf_mpu (struct address_info *hw_config)
-
-{
-	(void) install_wf_mpu ();
-}
-
-void
-unload_wf_mpu (void)
-{
-	uninstall_wf_mpu ();
-}
-
-#endif OSS_SUPPORT
-
-#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE
-
-
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.49/linux/drivers/usb/Config.in	Thu Mar  2 14:36:23 2000
+++ linux/drivers/usb/Config.in	Mon Mar  6 14:30:27 2000
@@ -9,11 +9,11 @@
 
 comment 'USB Controllers'
    dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-   if [ "$CONFIG_USB_UHCI" != "n" ]; then
+   if [ "$CONFIG_USB_UHCI" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool '    USB-UHCI High Bandwidth (EXPERIMENTAL)' CONFIG_USB_UHCI_HIGH_BANDWIDTH
    fi
    dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-   if [ "$CONFIG_USB_UHCI_ALT" != "n" ]; then
+   if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool '    UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
    fi
    dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
@@ -30,9 +30,11 @@
    if [ "$CONFIG_USB_SERIAL" != "n" ]; then
       bool '    USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
       bool '    USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR
-      bool '    USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT
-      bool '    USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO
-      bool '    USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA
+      if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+         bool '    USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT
+         bool '    USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO
+         bool '    USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA
+      fi
    fi
    dep_tristate '  USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
@@ -45,7 +47,7 @@
    dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
    dep_tristate '  PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB
-   dep_tristate '  USB ADMteks Pegasus based devices support' CONFIG_USB_PEGASUS $CONFIG_USB
+   dep_tristate '  USB ADMtek Pegasus-based device support' CONFIG_USB_PEGASUS $CONFIG_USB
    dep_tristate '  USB Diamond Rio500 support' CONFIG_USB_RIO500 $CONFIG_USB
    
 comment 'USB HID'
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.49/linux/drivers/usb/acm.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/usb/acm.c	Tue Mar  7 11:24:19 2000
@@ -134,6 +134,7 @@
 	struct tty_struct *tty;				/* the coresponding tty */
 	struct urb ctrlurb, readurb, writeurb;		/* urbs */
 	struct acm_line line;				/* line coding (bits, stop, parity) */
+	struct tq_struct tqueue;			/* task queue for line discipline waking up */
 	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
 	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
 	unsigned int writesize;				/* max packet size for the output bulk endpoint */
@@ -251,13 +252,22 @@
 static void acm_write_bulk(struct urb *urb)
 {
 	struct acm *acm = (struct acm *)urb->context;
-	struct tty_struct *tty = acm->tty;
 
 	if (!ACM_READY(acm)) return;
 
 	if (urb->status)
 		dbg("nonzero write bulk status received: %d", urb->status);
 
+	queue_task(&acm->tqueue, &tq_scheduler);
+}
+
+static void acm_softint(void *private)
+{
+	struct acm *acm = private;
+	struct tty_struct *tty = acm->tty;
+
+ 	if (!ACM_READY(acm)) return;
+
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
 		(tty->ldisc.write_wakeup)(tty);
 
@@ -534,6 +544,9 @@
 		acm->iface = cfacm->interface;
 		acm->minor = minor;
 		acm->dev = dev;
+
+		acm->tqueue.routine = acm_softint;
+		acm->tqueue.data = acm;
 
 		if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
 			err("out of memory");
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
--- v2.3.49/linux/drivers/usb/devices.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/usb/devices.c	Tue Mar  7 10:52:41 2000
@@ -165,8 +165,10 @@
 	if (start > end)
 		return start;
 	start += sprintf(start, format_endpt, desc->bEndpointAddress,
+			 (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL
+			 	? 'B' :			/* bidirectional */
 			 (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
-			 desc->bmAttributes, EndpointType[desc->bmAttributes & 3],
+			 desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK],
 			 desc->wMaxPacketSize, desc->bInterval);
 	return start;
 }
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.3.49/linux/drivers/usb/inode.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/usb/inode.c	Mon Mar  6 15:49:21 2000
@@ -212,9 +212,7 @@
 }
 
 static struct dentry_operations usbdevfs_dentry_operations = {
-        usbdevfs_revalidate,    /* d_revalidate */
-        NULL,                   /* d_hash */
-        NULL,                   /* d_compare */
+	d_revalidate:	usbdevfs_revalidate,
 };
 
 static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/keyspan_pda_fw.h linux/drivers/usb/keyspan_pda_fw.h
--- v2.3.49/linux/drivers/usb/keyspan_pda_fw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/keyspan_pda_fw.h	Tue Mar  7 11:24:19 2000
@@ -0,0 +1,93 @@
+/*
+ * keyspan_pda_fw.h
+ *
+ * Generated from keyspan_pda.s by ezusb_convert.pl
+ * This file is presumed to be under the same copyright as the source file
+ * from which it was derived.
+ */
+
+static const struct ezusb_hex_record keyspan_pda_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x02, 0x00} },
+{ 0x0023,	4,	{0x02, 0x05, 0x5f, 0x00} },
+{ 0x0043,	4,	{0x02, 0x01, 0x00, 0x00} },
+{ 0x0030,	5,	{0x00, 0x00, 0x00, 0x00, 0x00} },
+{ 0x0100,	16,	{0x02, 0x02, 0x96, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00} },
+{ 0x0110,	16,	{0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00} },
+{ 0x0120,	16,	{0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x04, 0x61, 0x00, 0x02, 0x04, 0x89, 0x00} },
+{ 0x0200,	16,	{0x75, 0x81, 0x5e, 0xe4, 0xf5, 0x32, 0xf5, 0x33, 0xf5, 0x30, 0xf5, 0x31, 0xf5, 0x34, 0xc2, 0x00} },
+{ 0x0210,	16,	{0xc2, 0x01, 0xa9, 0x00, 0x74, 0xfe, 0x90, 0x10, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x74, 0xfd, 0x90} },
+{ 0x0220,	16,	{0x11, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x74, 0x02, 0x90, 0x7f, 0x9d, 0xf0, 0x74, 0x00, 0x90, 0x7f} },
+{ 0x0230,	16,	{0x97, 0xf0, 0x74, 0x86, 0x90, 0x7f, 0x9e, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f} },
+{ 0x0240,	16,	{0xaf, 0xe0, 0xd2, 0xe0, 0xf0, 0x74, 0x01, 0x90, 0x7f, 0xab, 0xf0, 0x90, 0x7f, 0xae, 0xf0, 0x90} },
+{ 0x0250,	16,	{0x7f, 0xac, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xad, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x74} },
+{ 0x0260,	16,	{0x84, 0x90, 0x7f, 0x98, 0xf0, 0x74, 0x00, 0xf5, 0x98, 0x75, 0xc8, 0x30, 0x7b, 0x05, 0x91, 0x20} },
+{ 0x0270,	16,	{0xd2, 0xca, 0x75, 0x98, 0x50, 0xd2, 0xe8, 0xd2, 0xaf, 0xd2, 0xac, 0x74, 0x00, 0xf5, 0x86, 0x90} },
+{ 0x0280,	16,	{0x7f, 0xd6, 0x74, 0x02, 0xf0, 0x79, 0x2e, 0x7a, 0x00, 0x7b, 0x00, 0xdb, 0xfe, 0xda, 0xfa, 0xd9} },
+{ 0x0290,	16,	{0xf6, 0x74, 0x06, 0xf0, 0x80, 0xfe, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85} },
+{ 0x02a0,	16,	{0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0x90, 0x7f} },
+{ 0x02b0,	16,	{0xe8, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0xa3, 0xe0, 0xfc, 0xe9, 0x54, 0x60, 0xb4} },
+{ 0x02c0,	16,	{0x00, 0x03, 0x02, 0x03, 0x39, 0xb4, 0x40, 0x6e, 0xba, 0x00, 0x0b, 0x12, 0x04, 0x20, 0x40, 0x03} },
+{ 0x02d0,	16,	{0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x01, 0x03, 0x02, 0x04, 0x0a, 0xba, 0x02, 0x03, 0x02} },
+{ 0x02e0,	16,	{0x04, 0x0a, 0xba, 0x03, 0x03, 0x02, 0x04, 0x44, 0xba, 0x04, 0x1e, 0xbb, 0x00, 0x0a, 0x90, 0x7f} },
+{ 0x02f0,	16,	{0x95, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x04, 0x02, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0x90} },
+{ 0x0300,	16,	{0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 0x02, 0x04, 0x02, 0xba, 0x05, 0x03, 0x02, 0x04, 0x0a, 0xba} },
+{ 0x0310,	16,	{0x06, 0x19, 0xbb, 0x00, 0x08, 0xe5, 0x33, 0xd3, 0x95, 0x32, 0x02, 0x03, 0xde, 0xbb, 0x01, 0x08} },
+{ 0x0320,	16,	{0xe5, 0x32, 0xc3, 0x95, 0x33, 0x02, 0x03, 0xde, 0x02, 0x04, 0x0a, 0xba, 0x07, 0x05, 0x8b, 0x34} },
+{ 0x0330,	16,	{0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0x02, 0x04, 0x0a, 0xba, 0x00, 0x20, 0xb9, 0x80, 0x10, 0x90} },
+{ 0x0340,	16,	{0x7f, 0x00, 0xe4, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x04, 0x02, 0xb9} },
+{ 0x0350,	16,	{0x82, 0x02, 0x80, 0xeb, 0xb9, 0x81, 0x02, 0x80, 0xe6, 0x02, 0x04, 0x0a, 0xba, 0x01, 0x0f, 0xbb} },
+{ 0x0360,	16,	{0x00, 0x03, 0x02, 0x04, 0x0a, 0xbb, 0x01, 0x03, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x03} },
+{ 0x0370,	16,	{0x0f, 0xbb, 0x00, 0x03, 0x02, 0x04, 0x0a, 0xbb, 0x01, 0x03, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a} },
+{ 0x0380,	16,	{0xba, 0x06, 0x56, 0xbc, 0x01, 0x0f, 0x90, 0x7f, 0xd4, 0x74, 0x06, 0xf0, 0x90, 0x7f, 0xd5, 0x74} },
+{ 0x0390,	16,	{0x12, 0xf0, 0x02, 0x04, 0x02, 0xbc, 0x02, 0x12, 0xbb, 0x00, 0x6f, 0x90, 0x7f, 0xd4, 0x74, 0x06} },
+{ 0x03a0,	16,	{0xf0, 0x90, 0x7f, 0xd5, 0x74, 0x24, 0xf0, 0x02, 0x04, 0x02, 0xbc, 0x03, 0x29, 0x74, 0x04, 0xc3} },
+{ 0x03b0,	16,	{0x9b, 0x40, 0x57, 0x60, 0x55, 0xeb, 0x2b, 0x90, 0x06, 0x44, 0x25, 0x82, 0xf5, 0x82, 0x74, 0x00} },
+{ 0x03c0,	16,	{0x35, 0x83, 0xf5, 0x83, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0x90, 0x7f, 0xd4, 0xe9, 0xf0, 0x90, 0x7f} },
+{ 0x03d0,	16,	{0xd5, 0xea, 0xf0, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x08, 0x0f, 0x74, 0x01, 0x90, 0x7f} },
+{ 0x03e0,	16,	{0x00, 0xf0, 0x74, 0x01, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x04, 0x02, 0xba, 0x09, 0x03, 0x02, 0x04} },
+{ 0x03f0,	16,	{0x02, 0xba, 0x0a, 0x05, 0x74, 0x00, 0x02, 0x03, 0xde, 0xba, 0x0b, 0x03, 0x02, 0x04, 0x02, 0x02} },
+{ 0x0400,	16,	{0x04, 0x0a, 0x90, 0x7f, 0xb4, 0x74, 0x02, 0xf0, 0x80, 0x09, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x0410,	16,	{0xf0, 0x80, 0x00, 0xd0, 0xe0, 0xd0, 0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32} },
+{ 0x0420,	16,	{0xeb, 0x20, 0xe7, 0x1e, 0xc3, 0x94, 0x0a, 0x50, 0x19, 0xeb, 0x23, 0x24, 0xfe, 0xf5, 0x82, 0x74} },
+{ 0x0430,	16,	{0x05, 0x34, 0x00, 0xf5, 0x83, 0xe0, 0xf5, 0xcb, 0xf5, 0xcd, 0xa3, 0xe0, 0xf5, 0xca, 0xf5, 0xcc} },
+{ 0x0440,	16,	{0xc3, 0x22, 0xd3, 0x22, 0xb9, 0x41, 0x11, 0xeb, 0x64, 0xff, 0x54, 0x84, 0xfb, 0x90, 0x7f, 0x98} },
+{ 0x0450,	16,	{0xe0, 0x54, 0x7b, 0x4b, 0xf0, 0x02, 0x04, 0x02, 0x90, 0x7f, 0x9b, 0xe0, 0x64, 0xff, 0x02, 0x03} },
+{ 0x0460,	16,	{0xde, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2} },
+{ 0x0470,	16,	{0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0x12, 0x05, 0xa0, 0xd0, 0xe0, 0xd0, 0x85} },
+{ 0x0480,	16,	{0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0} },
+{ 0x0490,	16,	{0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xaa, 0x74, 0x04} },
+{ 0x04a0,	16,	{0xf0, 0x90, 0x7f, 0xc9, 0xe0, 0xf9, 0xe4, 0xf5, 0x86, 0x90, 0x7d, 0xc0, 0x75, 0x85, 0x10, 0x85} },
+{ 0x04b0,	16,	{0x32, 0x84, 0xe0, 0x05, 0x86, 0x05, 0x84, 0xf0, 0xe5, 0x84, 0xb5, 0x33, 0x02, 0x80, 0x09, 0x05} },
+{ 0x04c0,	16,	{0x32, 0x05, 0x86, 0xa3, 0xd9, 0xec, 0x80, 0x00, 0x90, 0x7f, 0xc9, 0xf0, 0xb1, 0x31, 0xd0, 0xe0} },
+{ 0x04d0,	16,	{0xd0, 0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xe4, 0xf5, 0x86, 0x90, 0x7f} },
+{ 0x04e0,	16,	{0xbc, 0xe0, 0x20, 0xe1, 0x4b, 0x90, 0x7d, 0x00, 0xe5, 0x32, 0xf0, 0xa3, 0xe5, 0x33, 0xf0, 0xa3} },
+{ 0x04f0,	16,	{0xe5, 0x30, 0xf0, 0xa3, 0xe5, 0x31, 0xf0, 0xa3, 0xe4, 0x30, 0x00, 0x01, 0x04, 0xf0, 0xa3, 0x05} },
+{ 0x0500,	16,	{0x86, 0x90, 0x10, 0x00, 0x79, 0x10, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xd9, 0xf6} },
+{ 0x0510,	16,	{0x05, 0x86, 0x74, 0xfc, 0xf0, 0xa3, 0x05, 0x86, 0x90, 0x11, 0x00, 0x79, 0x10, 0xe0, 0xa3, 0x05} },
+{ 0x0520,	16,	{0x86, 0xf0, 0xa3, 0x05, 0x86, 0xd9, 0xf6, 0xe4, 0xf5, 0x86, 0x90, 0x7f, 0xbd, 0x74, 0x26, 0xf0} },
+{ 0x0530,	16,	{0x22, 0x20, 0x00, 0x13, 0xe5, 0x32, 0xb5, 0x33, 0x01, 0x22, 0x05, 0x33, 0x75, 0x83, 0x10, 0x85} },
+{ 0x0540,	16,	{0x33, 0x82, 0xe0, 0xf5, 0x99, 0xd2, 0x00, 0x74, 0x00, 0xb5, 0x34, 0x01, 0x22, 0xe5, 0x33, 0xd3} },
+{ 0x0550,	16,	{0x95, 0x32, 0xc3, 0x95, 0x34, 0x40, 0xf5, 0x75, 0x34, 0x00, 0xd2, 0x01, 0x02, 0x05, 0xa0, 0xc0} },
+{ 0x0560,	16,	{0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0x30, 0x99, 0x07, 0xc2, 0x99} },
+{ 0x0570,	16,	{0xc2, 0x00, 0x12, 0x05, 0x34, 0x30, 0x98, 0x05, 0x12, 0x05, 0x8a, 0xc2, 0x98, 0xd0, 0xe0, 0xd0} },
+{ 0x0580,	16,	{0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0x75, 0x83, 0x11, 0x85, 0x30, 0x82} },
+{ 0x0590,	16,	{0x05, 0x82, 0xe5, 0x99, 0xf0, 0xe5, 0x82, 0xb5, 0x31, 0x01, 0x22, 0x05, 0x30, 0xb1, 0xa0, 0x22} },
+{ 0x05a0,	16,	{0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x38, 0x20, 0x01, 0x36, 0xe5, 0x30, 0xb5, 0x31, 0x01, 0x22} },
+{ 0x05b0,	16,	{0xe4, 0xf5, 0x86, 0x75, 0x83, 0x11, 0x05, 0x86, 0x90, 0x7e, 0x00, 0xf0, 0xa3, 0x05, 0x86, 0x79} },
+{ 0x05c0,	16,	{0x01, 0xe5, 0x30, 0xb5, 0x31, 0x02, 0x80, 0x10, 0x05, 0x31, 0x85, 0x31, 0x82, 0xe0, 0x05, 0x86} },
+{ 0x05d0,	16,	{0xf0, 0xa3, 0x05, 0x86, 0x09, 0xb9, 0x40, 0xe9, 0x90, 0x7f, 0xb9, 0xe9, 0x60, 0x01, 0xf0, 0x22} },
+{ 0x05e0,	16,	{0xc2, 0x01, 0xe4, 0xf5, 0x86, 0x90, 0x7e, 0x00, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x05f0,	16,	{0x7f, 0xb9, 0xf0, 0x22, 0xc2, 0x99, 0xf5, 0x99, 0x30, 0x99, 0xfd, 0xc2, 0x99, 0x22, 0xe5, 0x5e} },
+{ 0x0600,	16,	{0xf6, 0x3c, 0xfd, 0x8f, 0xfe, 0xc8, 0xff, 0x64, 0xff, 0xb2, 0xff, 0xd9, 0xff, 0xed, 0xff, 0xf3} },
+{ 0x0610,	16,	{0xff, 0xfa, 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab} },
+{ 0x0620,	16,	{0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00} },
+{ 0x0630,	16,	{0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01, 0x07, 0x05, 0x02} },
+{ 0x0640,	16,	{0x02, 0x40, 0x00, 0x00, 0x06, 0x4c, 0x06, 0x50, 0x06, 0x72, 0x06, 0xa0, 0x04, 0x03, 0x00, 0x00} },
+{ 0x0650,	16,	{0x22, 0x03, 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00} },
+{ 0x0660,	16,	{0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00} },
+{ 0x0670,	16,	{0x73, 0x00, 0x2e, 0x03, 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00} },
+{ 0x0680,	16,	{0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00} },
+{ 0x0690,	16,	{0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00} },
+{ 0x06a0,	6,	{0x06, 0x03, 0x34, 0x00, 0x37, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.3.49/linux/drivers/usb/usb-ohci.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/usb/usb-ohci.c	Fri Mar  3 21:34:45 2000
@@ -1264,7 +1264,7 @@
 	int status = TD_CC_NOERROR;
 	
 	__u32 datab[4];
-	__u8  * data_buf = datab;
+	__u8  * data_buf = (__u8 *) datab;
 	
  	__u16 bmRType_bReq;
 	__u16 wValue; 
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb-serial.c linux/drivers/usb/usb-serial.c
--- v2.3.49/linux/drivers/usb/usb-serial.c	Sat Feb 26 22:31:50 2000
+++ linux/drivers/usb/usb-serial.c	Tue Mar  7 11:24:19 2000
@@ -14,6 +14,12 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (03/06/2000) gkh
+ *	Added the keyspan pda code from Brian Warner <warner@lothar.com>
+ *	Moved a bunch of the port specific stuff into its own structure. This
+ *	is in anticipation of the true multiport devices (there's a bug if you
+ *	try to access more than one port of any multiport device right now)
+ *
  * (02/21/2000) gkh
  *	Made it so that any serial devices only have to specify which functions
  *	they want to overload from the generic function calls (great, 
@@ -178,6 +184,15 @@
 #include "whiteheat.h"		/* firmware for the ConnectTech WhiteHEAT device */
 #endif
 
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+struct ezusb_hex_record {
+	__u16 address;
+	__u8 data_size;
+	__u8 data[16];
+};
+#include "keyspan_pda_fw.h"
+#endif
+
 #include "usb-serial.h"
 
 /* parity check flag */
@@ -214,23 +229,9 @@
 
 static struct usb_serial *get_serial_by_minor (int minor)
 {
-	int i;
-
 	dbg("get_serial_by_minor %d", minor);
 
-	if (serial_table[minor] == NULL)
-		return (NULL);
-
-	if (serial_table[minor] != SERIAL_PTR_EMPTY)
-		return (serial_table[minor]);
-
-	i = minor;
-	while (serial_table[i] == SERIAL_PTR_EMPTY) {
-		if (i == 0)
-			return (NULL);
-		--i;
-		}
-	return (serial_table[i]);
+	return serial_table[minor];
 }
 
 
@@ -263,10 +264,10 @@
 		*minor = i;
 		dbg("minor base = %d", *minor);
 		for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
-			serial_table[i] = SERIAL_PTR_EMPTY;
-		return (serial);
+			serial_table[i] = serial;
+		return serial;
 		}
-	return (NULL);
+	return NULL;
 }
 
 
@@ -317,7 +318,7 @@
 	if (response < 0) {
 		err("ezusb_set_reset %d failed", reset_bit);
 	}
-	return (response);
+	return response;
 }
 
 #endif	/* USES_EZUSB_FUNCTIONS */
@@ -382,8 +383,8 @@
 		dbg("serial->type == NULL!");
 		return;
 	}
-	if (!serial->active[port]) {
-		dbg ("device already open");
+	if (!serial->port[port].active) {
+		dbg ("device not opened");
 		return;
 	}
 
@@ -412,7 +413,7 @@
 		dbg("serial->type == NULL!");
 		return (-ENODEV);
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not opened");
 		return (-EINVAL);
 	}
@@ -442,7 +443,7 @@
 		dbg("serial->type == NULL!");
 		return (-ENODEV);
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not open");
 		return (-EINVAL);
 	}
@@ -472,7 +473,7 @@
 		dbg("serial->type == NULL!");
 		return (-ENODEV);
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not open");
 		return (-EINVAL);
 	}
@@ -502,7 +503,7 @@
 		dbg("serial->type == NULL!");
 		return;
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not open");
 		return;
 	}
@@ -534,7 +535,7 @@
 		dbg("serial->type == NULL!");
 		return;
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not open");
 		return;
 	}
@@ -571,7 +572,7 @@
 		dbg("serial->type == NULL!");
 		return -ENODEV;
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not open");
 		return -ENODEV;
 	}
@@ -606,7 +607,7 @@
 		dbg("serial->type == NULL!");
 		return;
 	}
-	if (!serial->active[port]) {
+	if (!serial->port[port].active) {
 		dbg ("device not open");
 		return;
 	}
@@ -622,6 +623,38 @@
 }
 
 
+static void serial_break (struct tty_struct *tty, int break_state)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	int port;	
+
+	if (!serial) {
+		dbg("serial == NULL!");
+		return;
+	}
+
+	port = MINOR(tty->device) - serial->minor;
+
+	dbg("serial_break port %d", port);
+	
+	/* do some sanity checking that we really have a device present */
+	if (!serial->type) {
+		dbg("serial->type == NULL!");
+		return;
+	}
+	if (!serial->port[port].active) {
+		dbg ("device not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is
+           available */
+	if (serial->type->break_ctl) {
+		serial->type->break_ctl(tty, break_state);
+	}
+}
+
+
 #ifdef CONFIG_USB_SERIAL_WHITEHEAT
 /*****************************************************************************
  * Connect Tech's White Heat specific driver functions
@@ -629,18 +662,19 @@
 static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("whiteheat_serial_open port %d", port);
+	dbg("whiteheat_serial_open port %d", portNumber);
 
-	if (serial->active[port]) {
+	if (port->active) {
 		dbg ("device already open");
 		return -EINVAL;
 	}
-	serial->active[port] = 1;
+	port->active = 1;
  
 	/*Start reading from the device*/
-	if (usb_submit_urb(&serial->read_urb[port]))
+	if (usb_submit_urb(&port->read_urb))
 		dbg("usb_submit_urb(read bulk) failed");
 
 	/* Need to do device specific setup here (control lines, baud rate, etc.) */
@@ -653,17 +687,18 @@
 static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("whiteheat_serial_close port %d", port);
+	dbg("whiteheat_serial_close port %d", portNumber);
 	
 	/* Need to change the control lines here */
 	/* FIXME */
 	
 	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (&serial->write_urb[port]);
-	usb_unlink_urb (&serial->read_urb[port]);
-	serial->active[port] = 0;
+	usb_unlink_urb (&port->write_urb);
+	usb_unlink_urb (&port->read_urb);
+	port->active = 0;
 }
 
 
@@ -798,19 +833,20 @@
 static int visor_serial_open (struct tty_struct *tty, struct file *filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("visor_serial_open port %d", port);
+	dbg("visor_serial_open port %d", portNumber);
 
-	if (serial->active[port]) {
+	if (port->active) {
 		dbg ("device already open");
 		return -EINVAL;
 	}
 
-	serial->active[port] = 1;
+	port->active = 1;
 
 	/*Start reading from the device*/
-	if (usb_submit_urb(&serial->read_urb[port]))
+	if (usb_submit_urb(&port->read_urb))
 		dbg("usb_submit_urb(read bulk) failed");
 
 	return (0);
@@ -819,10 +855,11 @@
 static void visor_serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 	unsigned char *transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
 	
-	dbg("visor_serial_close port %d", port);
+	dbg("visor_serial_close port %d", portNumber);
 			 
 	if (!transfer_buffer) {
 		err("visor_serial_close: kmalloc(%d) failed.", 0x12);
@@ -833,9 +870,9 @@
 	}
 
 	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (&serial->write_urb[port]);
-	usb_unlink_urb (&serial->read_urb[port]);
-	serial->active[port] = 0;
+	usb_unlink_urb (&port->write_urb);
+	usb_unlink_urb (&port->read_urb);
+	port->active = 0;
 }
 
 
@@ -846,7 +883,7 @@
 
 	dbg("visor_throttle port %d", port);
 
-	usb_unlink_urb (&serial->read_urb[port]);
+	usb_unlink_urb (&serial->port[port].read_urb);
 
 	return;
 }
@@ -859,7 +896,7 @@
 
 	dbg("visor_unthrottle port %d", port);
 
-	if (usb_unlink_urb (&serial->read_urb[port]))
+	if (usb_unlink_urb (&serial->port[port].read_urb))
 		dbg("usb_submit_urb(read bulk) failed");
 
 	return;
@@ -947,16 +984,17 @@
 static int  ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 	char buf[1]; /* Needed for the usb_control_msg I think */
-	int port = MINOR(tty->device) - serial->minor;
 
-	dbg("ftdi_sio_serial_open port %d", port);
+	dbg("ftdi_sio_serial_open port %d", portNumber);
 
-	if (serial->active[port]) {
+	if (port->active) {
 		dbg ("device already open");
 		return -EINVAL;
 	}
-	serial->active[port] = 1;
+	port->active = 1;
 
 	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
@@ -1024,10 +1062,9 @@
 	}
 	
 	/*Start reading from the device*/
-	if (usb_submit_urb(&serial->read_urb[port]))
+	if (usb_submit_urb(&port->read_urb))
 		dbg("usb_submit_urb(read bulk) failed");
 
-
 	return (0);
 }
 
@@ -1035,10 +1072,11 @@
 static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 	char buf[1];
-	int port = MINOR(tty->device) - serial->minor;
 
-	dbg("ftdi_sio_serial_close port %d", port);
+	dbg("ftdi_sio_serial_close port %d", portNumber);
 	
 	/* FIXME - might be able to do both simultaneously */
 	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -1059,9 +1097,9 @@
 	/* FIXME Should I flush the device here? - not doing it for now */
 
 	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (&serial->write_urb[port]);
-	usb_unlink_urb (&serial->read_urb[port]);
-	serial->active[port] = 0;
+	usb_unlink_urb (&port->write_urb);
+	usb_unlink_urb (&port->read_urb);
+	port->active = 0;
 }
 
 
@@ -1075,42 +1113,44 @@
 				  const unsigned char *buf, int count)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 	const int data_offset = 1;
 
-	dbg("ftdi_sio_serial_write port %d, %d bytes", port, count);
+	dbg("ftdi_sio_serial_write port %d, %d bytes", portNumber, count);
 
 	if (count == 0) {
 		dbg("write request of 0 bytes");
-		return (0);
+		return 0;
 	}
 
 	/* only do something if we have a bulk out endpoint */
 	if (serial->num_bulk_out) {
-		unsigned char *first_byte = serial->write_urb[port].transfer_buffer;
+		unsigned char *first_byte = port->write_urb.transfer_buffer;
 
-		if (serial->write_urb[port].status == -EINPROGRESS) {
+		if (port->write_urb.status == -EINPROGRESS) {
 			dbg ("already writing");
-			return (0);
+			return 0;
 		}
 
 		count += data_offset;
-		count = (count > serial->bulk_out_size[port]) ? 
-			serial->bulk_out_size[port] : count;
-
+		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+		if (count == 0) {
+			return 0;
+		}
 
 		/* Copy in the data to send */
 		if (from_user) {
-			copy_from_user(serial->write_urb[port].transfer_buffer + data_offset , 
+			copy_from_user(port->write_urb.transfer_buffer + data_offset , 
 				       buf, count - data_offset );
 		}
 		else {
-			memcpy(serial->write_urb[port].transfer_buffer + data_offset,
+			memcpy(port->write_urb.transfer_buffer + data_offset,
 			       buf, count - data_offset );
 		}  
 
 		/* Write the control byte at the front of the packet*/
-		first_byte = serial->write_urb[port].transfer_buffer;
+		first_byte = port->write_urb.transfer_buffer;
 		*first_byte = 1 | ((count-data_offset) << 2) ; 
 
 #ifdef DEBUG
@@ -1133,20 +1173,18 @@
 		}
 
 #endif
-
-
 		/* send the data out the bulk port */
-		serial->write_urb[port].transfer_buffer_length = count;
+		port->write_urb.transfer_buffer_length = count;
 
-		if (usb_submit_urb(&serial->write_urb[port]))
+		if (usb_submit_urb(&port->write_urb))
 			dbg("usb_submit_urb(write bulk) failed");
 
-		dbg("write returning: %d",count - data_offset);
+		dbg("write returning: %d", count - data_offset);
 		return (count - data_offset);
 	}
 	
 	/* no bulk out, so return 0 bytes written */
-	return (0);
+	return 0;
 } 
 
 
@@ -1195,6 +1233,7 @@
 	return;
 } /* ftdi_sio_serial_read_bulk_callback */
 
+
 static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
@@ -1264,6 +1303,7 @@
 	return;
 }
 
+
 /*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
 static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
@@ -1347,6 +1387,8 @@
 					       urb_value , 0,
 					       buf, 0, HZ * 5));
 	}
+
+	return -ENOIOCTLCMD;
 }
 
 #endif	/* CONFIG_USB_SERIAL_FTDI_SIO */
@@ -1356,57 +1398,597 @@
 /*****************************************************************************
  * Keyspan PDA specific driver functions
  *****************************************************************************/
-static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp)
+
+static void keyspan_pda_rx_interrupt (struct urb *urb)
+{
+	struct usb_serial *serial = (struct usb_serial *) urb->context;
+	struct tty_struct *tty = serial->tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+
+	/* the urb might have been killed. */
+	if (urb->status)
+		return;
+	
+	/* see if the message is data or a status interrupt */
+	switch (data[0]) {
+	case 0:
+		/* rest of message is rx data */
+		if (urb->actual_length) {
+			for (i = 1; i < urb->actual_length ; ++i) {
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+			tty_flip_buffer_push(tty);
+		}
+		break;
+	case 1:
+		/* status interrupt */
+		dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
+		switch (data[1]) {
+		case 1: /* modemline change */
+			break;
+		case 2: /* tx unthrottle interrupt */
+			serial->tx_throttled = 0;
+			wake_up(&serial->write_wait); /* wake up writer */
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* INT urbs are automatically re-submitted */
+}
+
+
+static void keyspan_pda_rx_throttle (struct tty_struct *tty)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
 	int port = MINOR(tty->device) - serial->minor;
 
-	dbg("keyspan_pda_serial_open port %d", port);
+	/* stop receiving characters. We just turn off the URB request, and
+	   let chars pile up in the device. If we're doing hardware
+	   flowcontrol, the device will signal the other end when its buffer
+	   fills up. If we're doing XON/XOFF, this would be a good time to
+	   send an XOFF, although it might make sense to foist that off
+	   upon the device too. */
 
-	if (serial->active[port]) {
-		dbg ("device already open");
+	dbg("keyspan_pda_rx_throttle port %d", port);
+	usb_unlink_urb(&serial->port[port].read_urb);
+}
+
+
+static void keyspan_pda_rx_unthrottle (struct tty_struct *tty)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	int port = MINOR(tty->device) - serial->minor;
+
+	/* just restart the receive interrupt URB */
+	dbg("keyspan_pda_rx_unthrottle port %d", port);
+	if (usb_submit_urb(&serial->port[port].read_urb))
+		dbg(" usb_submit_urb(read urb) failed");
+	return;
+}
+
+
+static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+{
+	int rc;
+	int bindex;
+
+	switch(baud) {
+		case 110: bindex = 0; break;
+		case 300: bindex = 1; break;
+		case 1200: bindex = 2; break;
+		case 2400: bindex = 3; break;
+		case 4800: bindex = 4; break;
+		case 9600: bindex = 5; break;
+		case 19200: bindex = 6; break;
+		case 38400: bindex = 7; break;
+		case 57600: bindex = 8; break;
+		case 115200: bindex = 9; break;
+		default: return -EINVAL;
+	}
+
+	/* rather than figure out how to sleep while waiting for this
+	   to complete, I just use the "legacy" API. */
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     0, /* set baud */
+			     USB_TYPE_VENDOR 
+			     | USB_RECIP_INTERFACE
+			     | USB_DIR_OUT, /* type */
+			     bindex, /* value */
+			     0, /* index */
+			     NULL, /* &data */
+			     0, /* size */
+			     2*HZ); /* timeout */
+	return(rc);
+}
+
+
+static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+	int value;
+	if (break_state == -1)
+		value = 1; /* start break */
+	else
+		value = 0; /* clear break */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			4, /* set break */
+			USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			value, 0, NULL, 0, 2*HZ);
+	/* there is something funky about this.. the TCSBRK that 'cu' performs
+	   ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
+	   seconds apart, but it feels like the break sent isn't as long as it
+	   is on /dev/ttyS0 */
+}
+
+
+static void keyspan_pda_set_termios (struct tty_struct *tty,
+				     struct termios *old_termios)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	unsigned int cflag = tty->termios->c_cflag;
+
+	/* cflag specifies lots of stuff: number of stop bits, parity, number
+	   of data bits, baud. What can the device actually handle?:
+	   CSTOPB (1 stop bit or 2)
+	   PARENB (parity)
+	   CSIZE (5bit .. 8bit)
+	   There is minimal hw support for parity (a PSW bit seems to hold the
+	   parity of whatever is in the accumulator). The UART either deals
+	   with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
+	   1 special, stop). So, with firmware changes, we could do:
+	   8N1: 10 bit
+	   8N2: 11 bit, extra bit always (mark?)
+	   8[EOMS]1: 11 bit, extra bit is parity
+	   7[EOMS]1: 10 bit, b0/b7 is parity
+	   7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
+
+	   HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+	   bit.
+
+	   For now, just do baud. */
+
+	switch (cflag & CBAUD) {
+		/* we could support more values here, just need to calculate
+		   the necessary divisors in the firmware. <asm/termbits.h>
+		   has the Bnnn constants. */
+		case B110: keyspan_pda_setbaud(serial, 110); break;
+		case B300: keyspan_pda_setbaud(serial, 300); break;
+		case B1200: keyspan_pda_setbaud(serial, 1200); break;
+		case B2400: keyspan_pda_setbaud(serial, 2400); break;
+		case B4800: keyspan_pda_setbaud(serial, 4800); break;
+		case B9600: keyspan_pda_setbaud(serial, 9600); break;
+		case B19200: keyspan_pda_setbaud(serial, 19200); break;
+		case B38400: keyspan_pda_setbaud(serial, 38400); break;
+		case B57600: keyspan_pda_setbaud(serial, 57600); break;
+		case B115200: keyspan_pda_setbaud(serial, 115200); break;
+		default: dbg("can't handle requested baud rate"); break;
+	}
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled.
+   DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
+   read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
+
+static int keyspan_pda_get_modem_info(struct usb_serial *serial,
+				      unsigned char *value)
+{
+	int rc;
+	unsigned char data;
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     3, /* get pins */
+			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
+			     0, 0, &data, 1, 2*HZ);
+	if (rc > 0)
+		*value = data;
+	return rc;
+}
+
+
+static int keyspan_pda_set_modem_info(struct usb_serial *serial,
+				      unsigned char value)
+{
+	int rc;
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     3, /* set pins */
+			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
+			     value, 0, NULL, 0, 2*HZ);
+	return rc;
+}
+
+
+static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file,
+			     unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+	int rc;
+	unsigned int value;
+	unsigned char status, mask;
+
+	switch (cmd) {
+	case TIOCMGET: /* get modem pins state */
+		rc = keyspan_pda_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		value =
+			((status & (1<<7)) ? TIOCM_DTR : 0) |
+			((status & (1<<6)) ? TIOCM_CAR : 0) |
+			((status & (1<<5)) ? TIOCM_RNG : 0) |
+			((status & (1<<4)) ? TIOCM_DSR : 0) |
+			((status & (1<<3)) ? TIOCM_CTS : 0) |
+			((status & (1<<2)) ? TIOCM_RTS : 0);
+		if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	case TIOCMSET: /* set a state as returned by MGET */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		status =
+			((value & TIOCM_DTR) ? (1<<7) : 0) |
+			((value & TIOCM_CAR) ? (1<<6) : 0) |
+			((value & TIOCM_RNG) ? (1<<5) : 0) |
+			((value & TIOCM_DSR) ? (1<<4) : 0) |
+			((value & TIOCM_CTS) ? (1<<3) : 0) |
+			((value & TIOCM_RTS) ? (1<<2) : 0);
+		rc = keyspan_pda_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMBIS: /* set bits in bitmask <arg> */
+	case TIOCMBIC: /* clear bits from bitmask <arg> */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		rc = keyspan_pda_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		mask =
+			((value & TIOCM_RTS) ? (1<<2) : 0) |
+			((value & TIOCM_DTR) ? (1<<7) : 0);
+		if (cmd == TIOCMBIS)
+			status |= mask;
+		else
+			status &= ~mask;
+		rc = keyspan_pda_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		return 0; /* TODO */
+	}
+	
+	return -ENOIOCTLCMD;
+}
+
+static int keyspan_pda_write(struct tty_struct * tty, int from_user, 
+			     const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	int port = MINOR(tty->device) - serial->minor;
+	int request_unthrottle = 0;
+	int rc = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* guess how much room is left in the device's ring buffer, and if we
+	   want to send more than that, check first, updating our notion of
+	   what is left. If our write will result in no room left, ask the
+	   device to give us an interrupt when the room available rises above
+	   a threshold, and hold off all writers (eventually, those using
+	   select() or poll() too) until we receive that unthrottle interrupt.
+	   Block if we can't write anything at all, otherwise write as much as
+	   we can. */
+
+	if (count == 0) {
+		dbg(" write request of 0 bytes");
+		return (0);
+	}
+
+	/* we might block because of:
+	   the TX urb is in-flight (wait until it completes)
+	   the device is full (wait until it says there is room)
+	*/
+	while (serial->port[port].write_urb.status == -EINPROGRESS) {
+		if (0 /* file->f_flags & O_NONBLOCK */) {
+			rc = -EAGAIN;
+			goto err;
+		}
+		interruptible_sleep_on(&serial->write_wait);
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			goto err;
+		}
+	}
+
+	/* at this point the URB is in our control, nobody else can submit it
+	   again (the only sudden transition was the one from EINPROGRESS to
+	   finished) */
+
+	/* the next potential block is that our TX process might be throttled.
+	   The transition from throttled->not happens because of an Rx
+	   interrupt, and the wake_up occurs during the same interrupt, so we
+	   have to be careful to avoid a race that would cause us to sleep
+	   forever. */
+
+	add_wait_queue(&serial->write_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (serial->tx_throttled) {
+		/* device can't accomodate any more characters. Sleep until it
+		   can. Woken up by an Rx interrupt message, which clears
+		   tx_throttled first. */
+		dbg(" tx_throttled, going to sleep");
+		if (signal_pending(current)) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&serial->write_wait, &wait);
+			dbg(" woke up because of signal");
+			rc = -ERESTARTSYS;
+			goto err;
+		}
+		schedule();
+		dbg(" woke up");
+	}
+	remove_wait_queue(&serial->write_wait, &wait);
+	set_current_state(TASK_RUNNING);
+
+	count = (count > serial->port[port].bulk_out_size) ? 
+		serial->port[port].bulk_out_size : count;
+	if (count > serial->tx_room) {
+		unsigned char room;
+		/* Looks like we might overrun the Tx buffer. Ask the device
+		   how much room it really has */
+		rc = usb_control_msg(serial->dev, 
+				     usb_rcvctrlpipe(serial->dev, 0),
+				     6, /* write_room */
+				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+				     | USB_DIR_IN,
+				     0, /* value: 0 means "remaining room" */
+				     0, /* index */
+				     &room,
+				     1,
+				     2*HZ);
+		if (rc < 0) {
+			dbg(" roomquery failed");
+			return rc; /* failed */
+		}
+		if (rc == 0) {
+			dbg(" roomquery returned 0 bytes");
+			return -EIO; /* device didn't return any data */
+		}
+		dbg(" roomquery says %d", room);
+		serial->tx_room = room;
+		if (count > serial->tx_room) {
+			/* we're about to completely fill the Tx buffer, so
+			   we'll be throttled afterwards. */
+			count = serial->tx_room;
+			request_unthrottle = 1;
+		}
+	}
+	serial->tx_room -= count;
+
+	if (count) {
+		/* now transfer data */
+		if (from_user) {
+			copy_from_user(serial->port[port].write_urb.transfer_buffer,
+				       buf, count);
+		}
+		else {
+			memcpy (serial->port[port].write_urb.transfer_buffer, 
+				buf, count);
+		}  
+		/* send the data out the bulk port */
+		serial->port[port].write_urb.transfer_buffer_length = count;
+		
+		if (usb_submit_urb(&serial->port[port].write_urb))
+			dbg(" usb_submit_urb(write bulk) failed");
+	}
+	else {
+		/* There wasn't any room left, so we are throttled until
+		   the buffer empties a bit */
+		request_unthrottle = 1;
+	}
+
+	if (request_unthrottle) {
+		dbg(" request_unthrottle");
+		/* ask the device to tell us when the tx buffer becomes
+		   sufficiently empty */
+		serial->tx_throttled = 1; /* block writers */
+		rc = usb_control_msg(serial->dev, 
+				     usb_sndctrlpipe(serial->dev, 0),
+				     7, /* request_unthrottle */
+				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+				     | USB_DIR_OUT,
+				     16, /* value: threshold */
+				     0, /* index */
+				     NULL,
+				     0,
+				     2*HZ);
+	}
+
+	return (count);
+ err:
+	return (rc);
+}
+
+
+static void keyspan_pda_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial *serial = (struct usb_serial *) urb->context;
+	struct tty_struct *tty = serial->tty; 
+
+	wake_up_interruptible(&serial->write_wait);
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+
+static int keyspan_pda_write_room (struct tty_struct *tty)
+{
+	struct usb_serial *serial = (struct usb_serial *)tty->driver_data; 
+
+	/* used by n_tty.c for processing of tabs and such. Giving it our
+	   conservative guess is probably good enough, but needs testing by
+	   running a console through the device. */
+
+	return (serial->tx_room);
+}
+
+
+static int keyspan_pda_chars_in_buffer (struct tty_struct *tty) 
+{
+	struct usb_serial *serial = (struct usb_serial *)tty->driver_data; 
+	unsigned char count;
+	int rc;
+
+	/* used by tty stuff to wait for output to drain. Go ask the
+	   device how much is still queued in the tx ring */
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     6, /* write_room */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_IN,
+			     1, /* value: 1 means chars_in_buffer */
+			     0, /* index */
+			     &count,
+			     1,
+			     2*HZ);
+	if (rc < 0)
+		return rc; /* failed */
+	if (rc == 0)
+		return -EIO; /* device didn't return any data */
+	return (count);
+}
+
+
+static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp)
+{
+	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
+	unsigned char room;
+	int rc;
+
+	if (port->active) {
 		return -EINVAL;
 	}
-	serial->active[port] = 1;
+	port->active = 1;
  
-	/*Start reading from the device*/
-	if (usb_submit_urb(&serial->read_urb[port]))
-		dbg("usb_submit_urb(read bulk) failed");
+	/* find out how much room is in the Tx ring */
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     6, /* write_room */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     &room,
+			     1,
+			     2*HZ);
+	if (rc < 0) {
+		dbg(" roomquery failed");
+		return rc; /* failed */
+	}
+	if (rc == 0) {
+		dbg(" roomquery returned 0 bytes");
+		return -EIO; /* device didn't return any data */
+	}
+	serial->tx_room = room;
+	serial->tx_throttled = room ? 0 : 1;
+
+	/* the normal serial device seems to always turn on DTR and RTS here,
+	   so do the same */
+	if (tty->termios->c_cflag & CBAUD)
+		keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+	else
+		keyspan_pda_set_modem_info(serial, 0);
 
-	/* Need to do device specific setup here (control lines, baud rate, etc.) */
-	/* FIXME */
+	/*Start reading from the device*/
+	if (usb_submit_urb(&port->read_urb))
+		dbg(" usb_submit_urb(read int) failed");
 
 	return (0);
 }
 
 
-static void keyspan_pda_serial_close(struct tty_struct *tty, struct file * filp)
+static void keyspan_pda_serial_close(struct tty_struct *tty, 
+				     struct file *filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
+
+	/* the normal serial device seems to always shut off DTR and RTS now */
+	if (tty->termios->c_cflag & HUPCL)
+		keyspan_pda_set_modem_info(serial, 0);
 
-	dbg("keyspan_pda_serial_close port %d", port);
-	
-	/* Need to change the control lines here */
-	/* FIXME */
-	
 	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (&serial->write_urb[port]);
-	usb_unlink_urb (&serial->read_urb[port]);
-	serial->active[port] = 0;
+	usb_unlink_urb (&port->write_urb);
+	usb_unlink_urb (&port->read_urb);
+	port->active = 0;
 }
 
 
-static int  keyspan_pda_startup (struct usb_serial *serial)
+/* download the firmware to a "fake" device (pre-renumeration) */
+static int keyspan_pda_fake_startup (struct usb_serial *serial)
 {
-	dbg("keyspan_pda_startup");
+	int response;
+	const struct ezusb_hex_record *record;
 
 	/* download the firmware here ... */
-	/* FIXME */
+	response = ezusb_set_reset(serial, 1);
+
+	record = &keyspan_pda_firmware[0];
+	while(record->address != 0xffff) {
+		response = ezusb_writememory(serial, record->address,
+					     (unsigned char *)record->data,
+					     record->data_size, 0xa0);
+		if (response < 0) {
+			err("ezusb_writememory failed for Keyspan PDA "
+			    "firmware (%d %04X %p %d)",
+			    response, 
+			    record->address, record->data, record->data_size);
+			break;
+		}
+		record++;
+	}
+	/* bring device out of reset. Renumeration will occur in a moment
+	   and the new device will bind to the real driver */
+	response = ezusb_set_reset(serial, 0);
 
 	/* we want this device to fail to have a driver assigned to it. */
 	return (1);
 }
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int keyspan_pda_startup (struct usb_serial *serial)
+{
+	struct usb_endpoint_descriptor *intin;
+	intin = serial->port[0].interrupt_in_endpoint;
+
+	/* set up the receive interrupt urb */
+	FILL_INT_URB(&serial->port[0].read_urb, serial->dev,
+		     usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
+		     serial->port[0].interrupt_in_buffer,
+		     intin->wMaxPacketSize,
+		     keyspan_pda_rx_interrupt,
+		     serial,
+		     intin->bInterval);
+
+	init_waitqueue_head(&serial->write_wait);
+	
+	return (0);
+}
+
 #endif	/* CONFIG_USB_SERIAL_KEYSPAN_PDA */
 
 
@@ -1416,20 +1998,21 @@
 static int generic_serial_open (struct tty_struct *tty, struct file *filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("generic_serial_open port %d", port);
+	dbg("generic_serial_open port %d", portNumber);
 
-	if (serial->active[port]) {
+	if (port->active) {
 		dbg ("device already open");
 		return -EINVAL;
 	}
-	serial->active[port] = 1;
+	port->active = 1;
  
 	/* if we have a bulk interrupt, start reading from it */
 	if (serial->num_bulk_in) {
 		/*Start reading from the device*/
-		if (usb_submit_urb(&serial->read_urb[port]))
+		if (usb_submit_urb(&port->read_urb))
 			dbg("usb_submit_urb(read bulk) failed");
 	}
 
@@ -1440,28 +2023,30 @@
 static void generic_serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("generic_serial_close port %d", port);
+	dbg("generic_serial_close port %d", portNumber);
 	
 	/* shutdown any bulk reads that might be going on */
 	if (serial->num_bulk_out) {
-		usb_unlink_urb (&serial->write_urb[port]);
+		usb_unlink_urb (&port->write_urb);
 	}
 	if (serial->num_bulk_in) {
-		usb_unlink_urb (&serial->read_urb[port]);
+		usb_unlink_urb (&port->read_urb);
 	}
 
-	serial->active[port] = 0;
+	port->active = 0;
 }
 
 
 static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial *serial = (struct usb_serial *) tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("generic_serial_write port %d", port);
+	dbg("generic_serial_write port %d", portNumber);
 
 	if (count == 0) {
 		dbg("write request of 0 bytes");
@@ -1470,24 +2055,24 @@
 
 	/* only do something if we have a bulk out endpoint */
 	if (serial->num_bulk_out) {
-		if (serial->write_urb[port].status == -EINPROGRESS) {
+		if (port->write_urb.status == -EINPROGRESS) {
 			dbg ("already writing");
 			return (0);
 		}
 
-		count = (count > serial->bulk_out_size[port]) ? serial->bulk_out_size[port] : count;
+		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
 		if (from_user) {
-			copy_from_user(serial->write_urb[port].transfer_buffer, buf, count);
+			copy_from_user(port->write_urb.transfer_buffer, buf, count);
 		}
 		else {
-			memcpy (serial->write_urb[port].transfer_buffer, buf, count);
+			memcpy (port->write_urb.transfer_buffer, buf, count);
 		}  
 
 		/* send the data out the bulk port */
-		serial->write_urb[port].transfer_buffer_length = count;
+		port->write_urb.transfer_buffer_length = count;
 
-		if (usb_submit_urb(&serial->write_urb[port]))
+		if (usb_submit_urb(&port->write_urb))
 			dbg("usb_submit_urb(write bulk) failed");
 
 		return (count);
@@ -1501,16 +2086,17 @@
 static int generic_write_room (struct tty_struct *tty) 
 {
 	struct usb_serial *serial = (struct usb_serial *)tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 	int room;
 
-	dbg("generic_write_room port %d", port);
+	dbg("generic_write_room port %d", portNumber);
 	
 	if (serial->num_bulk_out) {
-		if (serial->write_urb[port].status == -EINPROGRESS)
+		if (port->write_urb.status == -EINPROGRESS)
 			room = 0;
 		else
-			room = serial->bulk_out_size[port];
+			room = port->bulk_out_size;
 		dbg("generic_write_room returns %d", room);
 		return (room);
 	}
@@ -1522,13 +2108,14 @@
 static int generic_chars_in_buffer (struct tty_struct *tty) 
 {
 	struct usb_serial *serial = (struct usb_serial *)tty->driver_data; 
-	int port = MINOR(tty->device) - serial->minor;
+	int portNumber = MINOR(tty->device) - serial->minor;
+	struct usb_serial_port *port = &serial->port[portNumber];
 
-	dbg("generic_chars_in_buffer port %d", port);
+	dbg("generic_chars_in_buffer port %d", portNumber);
 	
 	if (serial->num_bulk_out) {
-		if (serial->write_urb[port].status == -EINPROGRESS) {
-			return (serial->bulk_out_size[port]);
+		if (port->write_urb.status == -EINPROGRESS) {
+			return (port->bulk_out_size);
 		}
 	}
 
@@ -1628,6 +2215,7 @@
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_serial *serial = NULL;
+	struct usb_serial_port *port;
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
@@ -1723,6 +2311,20 @@
 				serial->num_bulk_out = num_bulk_out;
 				serial->num_interrupt_in = num_interrupt_in;
 
+				/* collect interrupt_in endpoints now, because
+				   the keyspan_pda startup function needs
+				   to know about them */
+				for (i = 0; i < num_interrupt_in; ++i) {
+					port = &serial->port[i];
+					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+					if (!port->interrupt_in_buffer) {
+						err("Couldn't allocate interrupt_in_buffer");
+						goto probe_error;
+					}
+					port->interrupt_in_endpoint = interrupt_in_endpoint[i];
+				}
+
 				/* if this device type has a startup function, call it */
 				if (type->startup) {
 					if (type->startup (serial)) {
@@ -1733,34 +2335,36 @@
 
 				/* set up the endpoint information */
 				for (i = 0; i < num_bulk_in; ++i) {
+					port = &serial->port[i];
 					buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
-					serial->bulk_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL);
-					if (!serial->bulk_in_buffer[i]) {
+					port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+					if (!port->bulk_in_buffer) {
 						err("Couldn't allocate bulk_in_buffer");
 						goto probe_error;
 					}
 					if (serial->type->read_bulk_callback) {
-						FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								serial->bulk_in_buffer[i], buffer_size, serial->type->read_bulk_callback, serial);
+						FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+								port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, serial);
 					} else {
-						FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								serial->bulk_in_buffer[i], buffer_size, generic_read_bulk_callback, serial);
+						FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+								port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, serial);
 					}
 				}
 
 				for (i = 0; i < num_bulk_out; ++i) {
-					serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize;
-					serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL);
-					if (!serial->bulk_out_buffer[i]) {
+					port = &serial->port[i];
+					port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
+					port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
+					if (!port->bulk_out_buffer) {
 						err("Couldn't allocate bulk_out_buffer");
 						goto probe_error;
 					}
 					if (serial->type->write_bulk_callback) {
-						FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial->type->write_bulk_callback, serial);
+						FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+								port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, serial);
 					} else {
-						FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								serial->bulk_out_buffer[i], serial->bulk_out_size[i], generic_write_bulk_callback, serial);
+						FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+								port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, serial);
 					}
 				}
 
@@ -1797,14 +2401,20 @@
 probe_error:
 	if (serial) {
 		for (i = 0; i < num_bulk_in; ++i)
-			if (serial->bulk_in_buffer[i])
-				kfree (serial->bulk_in_buffer[i]);
+			if (serial->port[i].bulk_in_buffer[i])
+				kfree (serial->port[i].bulk_in_buffer);
 		for (i = 0; i < num_bulk_out; ++i)
-			if (serial->bulk_out_buffer[i])
-				kfree (serial->bulk_out_buffer[i]);
+			if (serial->port[i].bulk_out_buffer)
+				kfree (serial->port[i].bulk_out_buffer);
 		for (i = 0; i < num_interrupt_in; ++i)
-			if (serial->interrupt_in_buffer[i])
-				kfree (serial->interrupt_in_buffer[i]);
+			if (serial->port[i].interrupt_in_buffer)
+				kfree (serial->port[i].interrupt_in_buffer);
+		
+		/* return the minor range that this device had */
+		return_serial (serial);
+
+		/* free up any memory that we allocated */
+		kfree (serial);
 	}
 	return NULL;
 }
@@ -1813,26 +2423,34 @@
 static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_serial *serial = (struct usb_serial *) ptr;
+	struct usb_serial_port *port;
 	int i;
 
 	if (serial) {
 		/* need to stop any transfers...*/
 		for (i = 0; i < serial->num_ports; ++i) {
-			usb_unlink_urb (&serial->write_urb[i]);
-			usb_unlink_urb (&serial->read_urb[i]);
-			serial->active[i] = 0;
+			port = &serial->port[i];
+			usb_unlink_urb (&port->write_urb);
+			usb_unlink_urb (&port->read_urb);
+			port->active = 0;
 		}
 
 		/* free up any memory that we allocated */
-		for (i = 0; i < serial->num_bulk_in; ++i)
-			if (serial->bulk_in_buffer[i])
-				kfree (serial->bulk_in_buffer[i]);
-		for (i = 0; i < serial->num_bulk_out; ++i)
-			if (serial->bulk_out_buffer[i])
-				kfree (serial->bulk_out_buffer[i]);
-		for (i = 0; i < serial->num_interrupt_in; ++i)
-			if (serial->interrupt_in_buffer[i])
-				kfree (serial->interrupt_in_buffer[i]);
+		for (i = 0; i < serial->num_bulk_in; ++i) {
+			port = &serial->port[i];
+			if (port->bulk_in_buffer)
+				kfree (port->bulk_in_buffer);
+		}
+		for (i = 0; i < serial->num_bulk_out; ++i) {
+			port = &serial->port[i];
+			if (port->bulk_out_buffer)
+				kfree (port->bulk_out_buffer);
+		}
+		for (i = 0; i < serial->num_interrupt_in; ++i) {
+			port = &serial->port[i];
+			if (port->interrupt_in_buffer)
+				kfree (port->interrupt_in_buffer);
+		}
 
 		for (i = 0; i < serial->num_ports; ++i) {
 			info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
@@ -1883,7 +2501,7 @@
 	stop:			NULL,
 	start:			NULL,
 	hangup:			NULL,
-	break_ctl:		NULL,
+	break_ctl:		serial_break,
 	wait_until_sent:	NULL,
 	send_xchar:		NULL,
 	read_proc:		NULL,
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb-serial.h linux/drivers/usb/usb-serial.h
--- v2.3.49/linux/drivers/usb/usb-serial.h	Sat Feb 26 22:31:50 2000
+++ linux/drivers/usb/usb-serial.h	Tue Mar  7 11:24:19 2000
@@ -44,7 +44,7 @@
 #define FTDI_SIO_SERIAL_CONVERTER_ID	0x8372
 #define KEYSPAN_VENDOR_ID		0x06cd
 #define KEYSPAN_PDA_FAKE_ID		0x0103
-#define KEYSPAN_PDA_ID			0x0103
+#define KEYSPAN_PDA_ID			0x0104 /* no clue */
 
 #define SERIAL_TTY_MAJOR	188	/* Nice legal number now */
 #define SERIAL_TTY_MINORS	16	/* Actually we are allowed 255, but this is good for now */
@@ -52,29 +52,45 @@
 
 #define MAX_NUM_PORTS	8	/* The maximum number of ports one device can grab at once */
 
+
+struct usb_serial_port {
+	struct usb_serial	*serial;	/* pointer back to the owner of this port */
+	struct tty_struct *	tty;		/* the coresponding tty for this device */
+	unsigned char		minor;
+	unsigned char		number;
+	char			active;		/* someone has this device open */
+
+	struct usb_endpoint_descriptor * interrupt_in_endpoint;
+	__u8			interrupt_in_interval;
+	unsigned char *		interrupt_in_buffer;
+	struct urb		control_urb;
+
+	unsigned char *		bulk_in_buffer;
+	struct urb		read_urb;
+
+	unsigned char *		bulk_out_buffer;
+	int			bulk_out_size;
+	struct urb		write_urb;
+	void *			private;	/* data private to the specific driver */
+};
+
 struct usb_serial {
 	struct usb_device *		dev;
 	struct usb_serial_device_type *	type;
-	void *				irq_handle;
-	unsigned int			irqpipe;
 	struct tty_struct *		tty;			/* the coresponding tty for this device */
 	unsigned char			minor;
 	unsigned char			num_ports;		/* the number of ports this device has */
-	char				active[MAX_NUM_PORTS];	/* someone has this device open */
+	char				num_interrupt_in;	/* number of interrupt in endpoints we have */
+	char				num_bulk_in;		/* number of bulk in endpoints we have */
+	char				num_bulk_out;		/* number of bulk out endpoints we have */
+	struct usb_serial_port		port[MAX_NUM_PORTS];
+
+	/* FIXME! These should move to the private area of the keyspan driver */
+	int			tx_room;
+	int			tx_throttled;
+	wait_queue_head_t 	write_wait;
 
-	char			num_interrupt_in;		/* number of interrupt in endpoints we have */
-	__u8			interrupt_in_interval[MAX_NUM_PORTS];
-	unsigned char *		interrupt_in_buffer[MAX_NUM_PORTS];
-	struct urb		control_urb[MAX_NUM_PORTS];
-
-	char			num_bulk_in;			/* number of bulk in endpoints we have */
-	unsigned char *		bulk_in_buffer[MAX_NUM_PORTS];
-	struct urb		read_urb[MAX_NUM_PORTS];
-
-	char			num_bulk_out;			/* number of bulk out endpoints we have */
-	unsigned char *		bulk_out_buffer[MAX_NUM_PORTS];
-	int			bulk_out_size[MAX_NUM_PORTS];
-	struct urb		write_urb[MAX_NUM_PORTS];
+	void *			private;		/* data private to the specific driver */
 };
 
 
@@ -101,8 +117,6 @@
 	char	num_bulk_out;
 	char	num_ports;		/* number of serial ports this device has */
 
-	void	*private;		/* data private to the specific driver */
-	
 	/* function call to make before accepting driver */
 	int (*startup) (struct usb_serial *serial);	/* return 0 to continue initialization, anything else to abort */
 	
@@ -113,13 +127,13 @@
 	int  (*write_room)(struct tty_struct *tty);
 	int  (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
 	void (*set_termios)(struct tty_struct *tty, struct termios * old);
+	void (*break_ctl)(struct tty_struct *tty, int break_state);
 	int  (*chars_in_buffer)(struct tty_struct *tty);
 	void (*throttle)(struct tty_struct * tty);
 	void (*unthrottle)(struct tty_struct * tty);
 	
 	void (*read_bulk_callback)(struct urb *urb);
 	void (*write_bulk_callback)(struct urb *urb);
-
 };
 
 
@@ -317,10 +331,31 @@
 
 
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/* function prototypes for a FTDI serial converter */
-static int  keyspan_pda_serial_open	(struct tty_struct *tty, struct file *filp);
-static void keyspan_pda_serial_close	(struct tty_struct *tty, struct file *filp);
+/* function prototypes for a Keyspan PDA serial converter */
+static int  keyspan_pda_serial_open	(struct tty_struct *tty, 
+					 struct file *filp);
+static void keyspan_pda_serial_close	(struct tty_struct *tty, 
+					 struct file *filp);
 static int  keyspan_pda_startup		(struct usb_serial *serial);
+static void keyspan_pda_rx_throttle	(struct tty_struct *tty);
+static void keyspan_pda_rx_unthrottle	(struct tty_struct *tty);
+static int  keyspan_pda_setbaud		(struct usb_serial *serial, int baud);
+static int  keyspan_pda_write_room	(struct tty_struct *tty);
+static int  keyspan_pda_write		(struct tty_struct *tty,
+					 int from_user,
+					 const unsigned char *buf,
+					 int count);
+static void keyspan_pda_write_bulk_callback (struct urb *urb);
+static int  keyspan_pda_chars_in_buffer (struct tty_struct *tty);
+static int  keyspan_pda_ioctl		(struct tty_struct *tty,
+					 struct file *file,
+					 unsigned int cmd,
+					 unsigned long arg);
+static void keyspan_pda_set_termios	(struct tty_struct *tty,
+					 struct termios *old);
+static void keyspan_pda_break_ctl	(struct tty_struct *tty,
+					 int break_state);
+static int  keyspan_pda_fake_startup	(struct usb_serial *serial);
 
 /* All of the device info needed for the Keyspan PDA serial converter */
 static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
@@ -336,24 +371,35 @@
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		NUM_DONT_CARE,
 	num_bulk_out:		NUM_DONT_CARE,
-	startup:		keyspan_pda_startup	
+	startup:		keyspan_pda_fake_startup
 };
 static struct usb_serial_device_type keyspan_pda_device = {
 	name:			"Keyspan PDA",
 	idVendor:		&keyspan_vendor_id,		/* the Keyspan PDA vendor ID */
 	idProduct:		&keyspan_pda_product_id,	/* the Keyspan PDA product id */
-	needs_interrupt_in:	MUST_HAVE_NOT,			/* this device must not have an interrupt in endpoint */
-	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
-	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
-	num_interrupt_in:	0,
-	num_bulk_in:		1,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		0,
 	num_bulk_out:		1,
 	num_ports:		1,
 	open:			keyspan_pda_serial_open,
 	close:			keyspan_pda_serial_close,
+	write:			keyspan_pda_write,
+	write_room:		keyspan_pda_write_room,
+	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
+	chars_in_buffer:	keyspan_pda_chars_in_buffer,
+	throttle:		keyspan_pda_rx_throttle,
+	unthrottle:		keyspan_pda_rx_unthrottle,
+	startup:		keyspan_pda_startup,
+	ioctl:			keyspan_pda_ioctl,
+	set_termios:		keyspan_pda_set_termios,
+	break_ctl:		keyspan_pda_break_ctl,
 };
 #endif
 
+
 /* To add support for another serial converter, create a usb_serial_device_type
    structure for that device, and add it to this list, making sure that the
    last  entry is NULL. */
@@ -385,11 +431,6 @@
 #else
 	#undef 	USES_EZUSB_FUNCTIONS
 #endif
-
-
-/* used to mark that a pointer is empty (and not NULL) */
-#define SERIAL_PTR_EMPTY ((void *)(-1))
-
 
 #endif	/* ifdef __LINUX_USB_SERIAL_H */
 
diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.49/linux/drivers/usb/usb.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/usb/usb.c	Mon Mar  6 14:30:27 2000
@@ -410,21 +410,27 @@
 {
 	unsigned ifnum;
 	unsigned rejected = 0;
+	unsigned claimed = 0;
 
 	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
 		/* if this interface hasn't already been claimed */
 		if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) {
 			if (usb_find_interface_driver(dev, ifnum))
 				rejected++;
+			else
+				claimed++;
 		}
 	}
  
 	if (rejected)
 		dbg("unhandled interfaces on device");
 
+	if (!claimed) {
+		warn("This device is not recognized by any installed USB driver.");
 #ifdef DEBUG
-	usb_show_device(dev);
+		usb_show_device(dev);
 #endif
+	}
 }
 
 /*
diff -u --recursive --new-file v2.3.49/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.49/linux/drivers/video/Config.in	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/Config.in	Tue Mar  7 11:06:44 2000
@@ -85,6 +85,7 @@
    if [ "$ARCH" = "i386" ]; then
       bool '  VESA VGA graphics console' CONFIG_FB_VESA
       tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
+      tristate '  Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA
       define_bool CONFIG_VIDEO_SELECT y
    fi
    if [ "$CONFIG_VISWS" = "y" ]; then
@@ -173,6 +174,7 @@
       tristate '    Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
       tristate '    VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
       tristate '    VGA characters/attributes support' CONFIG_FBCON_VGA
+      tristate '    HGA monochrome support (EXPERIMENTAL)' CONFIG_FBCON_HGA
    else
       # Guess what we need
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
@@ -329,6 +331,13 @@
       else
 	 if [ "$CONFIG_FB_VGA16" = "m" ]; then
 	    define_tristate CONFIG_FBCON_VGA_PLANES m
+	 fi
+      fi
+      if [ "$CONFIG_FB_HGA" = "y" ]; then
+	 define_tristate CONFIG_FBCON_HGA y
+      else
+	 if [ "$CONFIG_FB_HGA" = "m" ]; then
+	    define_tristate CONFIG_FBCON_HGA m
 	 fi
       fi
    fi
diff -u --recursive --new-file v2.3.49/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.49/linux/drivers/video/Makefile	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/Makefile	Sat Mar  4 20:03:50 2000
@@ -21,7 +21,7 @@
 		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
 		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
 		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o fbcon-vga8-planes.o \
-		  matrox/matroxfb.o cyber2000fb.o
+		  matrox/matroxfb.o cyber2000fb.o fbcon-hga.o
 
 # Object file lists.
 obj-y          :=
@@ -85,9 +85,6 @@
 obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
 obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
 obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
-obj-$(CONFIG_FB_SUN3)             += sun3fb.o
-obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
-obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
 
 ifeq ($(CONFIG_FB_MATROX),y)
 SUB_DIRS			  += matrox
@@ -109,6 +106,11 @@
   endif
 endif
 
+obj-$(CONFIG_FB_SUN3)             += sun3fb.o
+obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
+obj-$(CONFIG_FB_HGA)              += hgafb.o  
+obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
+
 # Generic Low Level Drivers
 
 obj-$(CONFIG_FBCON_AFB)           += fbcon-afb.o
@@ -126,6 +128,7 @@
 obj-$(CONFIG_FBCON_MAC)           += fbcon-mac.o
 obj-$(CONFIG_FBCON_MFB)           += fbcon-mfb.o
 obj-$(CONFIG_FBCON_VGA)           += fbcon-vga.o
+obj-$(CONFIG_FBCON_HGA)           += fbcon-hga.o
 
 # Extract lists of the multi-part drivers.
 # The 'int-*' lists are the intermediate files used to build the multi's.
diff -u --recursive --new-file v2.3.49/linux/drivers/video/fbcmap.c linux/drivers/video/fbcmap.c
--- v2.3.49/linux/drivers/video/fbcmap.c	Tue Jun  1 23:25:48 1999
+++ linux/drivers/video/fbcmap.c	Tue Mar  7 10:52:41 2000
@@ -16,22 +16,6 @@
 
 #include <asm/uaccess.h>
 
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-    switch (fsfromto) {
-    	case 0:
-    	    memcpy(to, from, len);
-    	    return;
-    	case 1:
-    	    copy_from_user(to, from, len);
-    	    return;
-    	case 2:
-    	    copy_to_user(to, from, len);
-    	    return;
-    }
-}
-
 static u16 red2[] = {
     0x0000, 0xaaaa
 };
@@ -148,11 +132,30 @@
     if (size < 0)
 	return;
     size *= sizeof(u16);
-    memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-    memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-    memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-    if (from->transp && to->transp)
-	memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
+    
+    switch (fsfromto) {
+    case 0:
+	memcpy(to->red+tooff, from->red+fromoff, size);
+	memcpy(to->green+tooff, from->green+fromoff, size);
+	memcpy(to->blue+tooff, from->blue+fromoff, size);
+	if (from->transp && to->transp)
+	    memcpy(to->transp+tooff, from->transp+fromoff, size);
+        break;
+    case 1:
+	copy_from_user(to->red+tooff, from->red+fromoff, size);
+	copy_from_user(to->green+tooff, from->green+fromoff, size);
+	copy_from_user(to->blue+tooff, from->blue+fromoff, size);
+	if (from->transp && to->transp)
+            copy_from_user(to->transp+tooff, from->transp+fromoff, size);
+	break;
+    case 2:
+	copy_to_user(to->red+tooff, from->red+fromoff, size);
+	copy_to_user(to->green+tooff, from->green+fromoff, size);
+	copy_to_user(to->blue+tooff, from->blue+fromoff, size);
+	if (from->transp && to->transp)
+	    copy_to_user(to->transp+tooff, from->transp+fromoff, size);
+	break;
+    }
 }
 
 
diff -u --recursive --new-file v2.3.49/linux/drivers/video/fbcon-hga.c linux/drivers/video/fbcon-hga.c
--- v2.3.49/linux/drivers/video/fbcon-hga.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/fbcon-hga.c	Sat Mar  4 20:03:50 2000
@@ -0,0 +1,245 @@
+/*
+ *  linux/drivers/video/fbcon-hga.c -- Low level frame buffer operations for
+ *				       the Hercules graphics adaptor
+ *
+ *	Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu)
+ *	Based on fbcon-mfb.c by Geert Uytterhoeven
+ *
+ * History:
+ *
+ * - Revision 0.1.0 (6 Dec 1999): comment changes
+ * - First release (25 Nov 1999)
+ * 
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-hga.h>
+
+#if 0
+#define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args)
+#else
+#define DPRINTK(args...)
+#endif
+
+#define HGA_ROWADDR(row) ((row%4)*8192 + (row>>2)*90)
+
+    /*
+     *  Hercules monochrome
+     */
+
+static inline u8* rowaddr(struct display *p, u_int row)
+{
+	return p->screen_base + HGA_ROWADDR(row);
+}
+	
+void fbcon_hga_setup(struct display *p)
+{
+	DPRINTK("fbcon_hga_setup: ll:%d\n", (int)p->line_length);
+
+	p->next_line = p->line_length;
+	p->next_plane = 0;
+}
+
+void fbcon_hga_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		     int height, int width)
+{
+	u8 *src, *dest;
+	u_int rows, y1, y2;
+	
+#if 0
+	if (sx == 0 && dx == 0 && width == p->next_line) {
+		src = p->screen_base+sy*fontheight(p)*width;
+		dest = p->screen_base+dy*fontheight(p)*width;
+		fb_memmove(dest, src, height*fontheight(p)*width);
+	} else 
+#endif
+	if (dy <= sy) {
+		y1 = sy*fontheight(p);
+		y2 = dy*fontheight(p);
+		for (rows = height*fontheight(p); rows--; ) {
+			src = rowaddr(p, y1)+sx;
+			dest = rowaddr(p, y2)+dx;
+			fb_memmove(dest, src, width);
+			y1++;
+			y2++;
+		}
+	} else {
+		y1 = (sy+height)*fontheight(p)-1;
+		y2 = (dy+height)*fontheight(p)-1;
+		for (rows = height*fontheight(p); rows--;) {
+			src = rowaddr(p, y1)+sx;
+			dest = rowaddr(p, y2)+dx;
+			fb_memmove(dest, src, width);
+			y1--;
+			y2--;
+		}
+	}
+}
+
+void fbcon_hga_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+		     int height, int width)
+{
+	u8 *dest;
+	u_int rows, y;
+	int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+	DPRINTK("fbcon_hga_clear: sx:%d, sy:%d, height:%d, width:%d\n", sx, sy, height, width);
+	
+	y = sy*fontheight(p);
+#if 0
+	if (sx == 0 && width == p->next_line) {
+		if (inverse) {
+			fb_memset255(dest, height*fontheight(p)*width);
+		} else {
+			fb_memclear(dest, height*fontheight(p)*width);
+		}
+	} else
+#endif	    
+	for (rows = height*fontheight(p); rows--; y++) {
+		dest = rowaddr(p, y)+sx;
+		if (inverse) {
+			fb_memset255(dest, width);
+		} else {
+			fb_memclear(dest, width);
+		}
+	}
+}
+
+void fbcon_hga_putc(struct vc_data *conp, struct display *p, int c, int yy,
+		    int xx)
+{
+	u8 *dest, *cdat;
+	u_int rows, y, bold, revs, underl;
+	u8 d;
+
+	cdat = p->fontdata+(c&p->charmask)*fontheight(p);
+	bold = attr_bold(p, c);
+	revs = attr_reverse(p, c);
+	underl = attr_underline(p, c);
+	y = yy*fontheight(p);
+
+	for (rows = fontheight(p); rows--; y++) {
+		d = *cdat++;
+		if (underl && !rows)
+			d = 0xff;
+		else if (bold)
+			d |= d>>1;
+		if (revs)
+			d = ~d;
+		dest = rowaddr(p, y)+xx;
+		*dest = d;
+	}
+}
+
+void fbcon_hga_putcs(struct vc_data *conp, struct display *p, 
+		     const unsigned short *s, int count, int yy, int xx)
+{
+	u8 *dest, *cdat;
+	u_int rows, y, y0, bold, revs, underl;
+	u8 d;
+	u16 c;
+	
+	bold = attr_bold(p,scr_readw(s));
+	revs = attr_reverse(p,scr_readw(s));
+	underl = attr_underline(p,scr_readw(s));
+	y0 = yy*fontheight(p);
+
+	while (count--) {
+		c = scr_readw(s++) & p->charmask;
+		cdat = p->fontdata+c*fontheight(p);
+		y = y0;
+		for (rows = fontheight(p); rows--; y++) {
+			d = *cdat++;
+	    		if (underl && !rows)
+				d = 0xff;
+	    		else if (bold)
+				d |= d>>1;
+	    		if (revs)
+				d = ~d;
+			dest = rowaddr(p, y)+xx;
+	    		*dest = d;
+		}
+		xx++;
+	}
+}
+
+void fbcon_hga_revc(struct display *p, int xx, int yy)
+{
+	u8 *dest;
+	u_int rows, y;
+
+	y = yy*fontheight(p);
+	for (rows = fontheight(p); rows--; y++) {
+		dest = rowaddr(p, y)+xx;
+		*dest = ~*dest;
+	}
+}
+
+void fbcon_hga_clear_margins(struct vc_data *conp, struct display *p,
+			     int bottom_only)
+{
+	u8 *dest;
+	u_int height, y;
+	int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
+
+	DPRINTK("fbcon_hga_clear_margins: enter\n");
+
+	/* No need to handle right margin. */
+
+	y = conp->vc_rows * fontheight(p);
+	for (height = p->var.yres - y; height-- > 0; y++) {
+		DPRINTK("fbcon_hga_clear_margins: y:%d, height:%d\n", y, height);
+		dest = rowaddr(p, y);
+		if (inverse) {
+			fb_memset255(dest, p->next_line);
+		} else {
+			fb_memclear(dest, p->next_line);
+		}
+	}
+}
+
+
+	/*
+	 *  `switch' for the low level operations
+	 */
+
+struct display_switch fbcon_hga = {
+	fbcon_hga_setup, fbcon_hga_bmove, fbcon_hga_clear, fbcon_hga_putc,
+	fbcon_hga_putcs, fbcon_hga_revc, NULL, NULL, fbcon_hga_clear_margins,
+	FONTWIDTH(8)
+};
+
+
+#ifdef MODULE
+int init_module(void)
+{
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+	/*
+	 *  Visible symbols for modules
+	 */
+
+EXPORT_SYMBOL(fbcon_hga);
+EXPORT_SYMBOL(fbcon_hga_setup);
+EXPORT_SYMBOL(fbcon_hga_bmove);
+EXPORT_SYMBOL(fbcon_hga_clear);
+EXPORT_SYMBOL(fbcon_hga_putc);
+EXPORT_SYMBOL(fbcon_hga_putcs);
+EXPORT_SYMBOL(fbcon_hga_revc);
+EXPORT_SYMBOL(fbcon_hga_clear_margins);
diff -u --recursive --new-file v2.3.49/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.3.49/linux/drivers/video/fbcon.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/video/fbcon.c	Sat Mar  4 20:03:50 2000
@@ -2301,7 +2301,7 @@
 	}
 #endif
 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
-    defined(CONFIG_FBCON_ILBM)
+    defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_HGA)
 
 	if (depth == 1 && (p->type == FB_TYPE_PACKED_PIXELS ||
 			   p->type == FB_TYPE_PLANES ||
@@ -2311,10 +2311,14 @@
 	    unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01
 		? 0x00 : 0xff;
 
+	    int is_hga = !strncmp(p->fb_info->modename, "HGA", 3);
 	    /* can't use simply memcpy because need to apply inverse */
 	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
 		src = logo + y1*LOGO_LINE;
-		dst = fb + y1*line + x/8;
+		if (is_hga)
+		    dst = fb + (y1%4)*8192 + (y1>>2)*line + x/8;
+		else
+		    dst = fb + y1*line + x/8;
 		for( x1 = 0; x1 < LOGO_LINE; ++x1 )
 		    fb_writeb(fb_readb(src++) ^ inverse, dst++);
 	    }
diff -u --recursive --new-file v2.3.49/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.49/linux/drivers/video/fbmem.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/fbmem.c	Sat Mar  4 20:03:50 2000
@@ -85,6 +85,8 @@
 extern int vesafb_setup(char*);
 extern int vga16fb_init(void);
 extern int vga16fb_setup(char*);
+extern int hgafb_init(void);
+extern int hgafb_setup(char*);
 extern int matroxfb_init(void);
 extern int matroxfb_setup(char*);
 extern int hpfb_init(void);
@@ -195,6 +197,9 @@
 #endif 
 #ifdef CONFIG_FB_VGA16
 	{ "vga16", vga16fb_init, vga16fb_setup },
+#endif 
+#ifdef CONFIG_FB_HGA
+	{ "hga", hgafb_init, hgafb_setup },
 #endif 
 #ifdef CONFIG_FB_MATROX
 	{ "matrox", matroxfb_init, matroxfb_setup },
diff -u --recursive --new-file v2.3.49/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- v2.3.49/linux/drivers/video/hgafb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/hgafb.c	Tue Mar  7 11:10:03 2000
@@ -0,0 +1,762 @@
+/*
+ * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device
+ * 
+ *      Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu)
+ *      Based on skeletonfb.c by Geert Uytterhoeven and
+ *               mdacon.c by Andrew Apted
+ *
+ * History:
+ *
+ * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for 
+ *                                  HGA-only systems
+ * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure
+ *                                 screen is cleared after rmmod
+ *                                 virtual resolutions
+ *                                 kernel parameter 'video=hga:font:{fontname}'
+ *                                 module parameter 'font={fontname}'
+ *                                 module parameter 'nologo={0|1}'
+ *                                 the most important: boot logo :)
+ * - Revision 0.1.0  (6 Dec 1999): faster scrolling and minor fixes
+ * - First release  (25 Nov 1999)
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/vga.h>
+#include <video/fbcon.h>
+#include <video/fbcon-hga.h>
+
+#ifdef MODULE
+
+#define INCLUDE_LINUX_LOGOBW
+#include <linux/linux_logo.h>
+
+#endif /* MODULE */
+
+#if 0
+#define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args)
+#else
+#define DPRINTK(args...)
+#endif
+
+#if 1
+#define CHKINFO(ret) if (info != &fb_info) { printk(KERN_DEBUG __FILE__": This should never happen, line:%d \n", __LINE__); return ret; }
+#else
+#define CHKINFO(ret)
+#endif
+
+/* Description of the hardware layout */
+
+static unsigned long hga_vram_base;		/* Base of video memory */
+static unsigned long hga_vram_len;		/* Size of video memory */
+
+#define HGA_TXT			0
+#define HGA_GFX			1
+
+static int hga_mode = -1;			/* 0 = txt, 1 = gfx mode */
+
+static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type;
+static char *hga_type_name;
+
+#define HGA_INDEX_PORT		0x3b4		/* Register select port */
+#define HGA_VALUE_PORT		0x3b5		/* Register value port */
+#define HGA_MODE_PORT		0x3b8		/* Mode control port */
+#define HGA_STATUS_PORT		0x3ba		/* Status and Config port */
+#define HGA_GFX_PORT		0x3bf		/* Graphics control port */
+
+/* HGA register values */
+
+#define HGA_CURSOR_BLINKING	0x00
+#define HGA_CURSOR_OFF		0x20
+#define HGA_CURSOR_SLOWBLINK	0x60
+
+#define HGA_MODE_GRAPHICS	0x02
+#define HGA_MODE_VIDEO_EN	0x08
+#define HGA_MODE_BLINK_EN	0x20
+#define HGA_MODE_GFX_PAGE1	0x80
+
+#define HGA_STATUS_HSYNC	0x01
+#define HGA_STATUS_VSYNC	0x80
+#define HGA_STATUS_VIDEO	0x08
+
+#define HGA_CONFIG_COL132	0x08
+#define HGA_GFX_MODE_EN		0x01
+#define HGA_GFX_PAGE_EN		0x02
+
+/* Framebuffer driver structures */
+
+static struct fb_var_screeninfo hga_default_var = {
+	720, 348,			/* xres, yres */
+	720, 348,			/* xres_virtual, yres_virtual */
+	0, 0,				/* xoffset, yoffset */
+	1,				/* bits_per_pixel */
+	0,				/* grayscale */
+	{0, 1, 0},			/* red */
+	{0, 1, 0},			/* green */
+	{0, 1, 0},			/* blue */
+	{0, 0, 0},			/* transp */ 
+	0,				/* nonstd (FB_NONSTD_HGA ?) */
+	0,				/* activate */
+	-1, -1,				/* height, width */
+	0,				/* accel_flags */
+	/* pixclock */
+	/* left_margin, right_margin */
+	/* upper_margin, lower_margin */
+	/* hsync_len, vsync_len */
+	/* sync */
+	/* vmode */
+};
+
+static struct fb_fix_screeninfo hga_fix = {
+	"HGA",				/* id */
+	(unsigned long) NULL,		/* smem_start */
+	0,				/* smem_len */
+	FB_TYPE_PACKED_PIXELS,		/* type (not sure) */
+	0,				/* type_aux (not sure) */
+	FB_VISUAL_MONO10,		/* visual */
+	8,				/* xpanstep */
+	8,				/* ypanstep */
+	0,				/* ywrapstep */
+	90,				/* line_length */
+	0,				/* mmio_start */
+	0,				/* mmio_len */
+	FB_ACCEL_NONE			/* accel */
+};
+
+static struct fb_info fb_info;
+static struct display disp;
+
+/* Don't assume that tty1 will be the initial current console. */
+static int currcon = -1; 
+static int release_io_port = 0;
+static int release_io_ports = 0;
+
+#ifdef MODULE
+static char *font = NULL;
+static int nologo = 0;
+#endif
+
+/* -------------------------------------------------------------------------
+ *
+ * Low level hardware functions
+ *
+ * ------------------------------------------------------------------------- */
+
+static void write_hga_b(unsigned int val, unsigned char reg)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	outb_p(reg, HGA_INDEX_PORT); 
+	outb_p(val, HGA_VALUE_PORT);
+
+	restore_flags(flags);
+}
+
+static void write_hga_w(unsigned int val, unsigned char reg)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	outb_p(reg,   HGA_INDEX_PORT); outb_p(val >> 8,   HGA_VALUE_PORT);
+	outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT);
+
+	restore_flags(flags);
+}
+
+static int test_hga_b(unsigned char val, unsigned char reg)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	outb_p(reg, HGA_INDEX_PORT); 
+	outb  (val, HGA_VALUE_PORT);
+
+	udelay(20); val = (inb_p(HGA_VALUE_PORT) == val);
+
+	restore_flags(flags);
+
+	return val;
+}
+
+static void hga_clear_screen(void)
+{
+	if (hga_mode == HGA_TXT)
+		memset((char *)hga_vram_base, ' ', hga_vram_len);
+	else if (hga_mode == HGA_GFX)
+		memset((char *)hga_vram_base, 0, hga_vram_len);
+}
+
+
+static void hga_txt_mode(void)
+{
+	outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT);
+	outb_p(0x00, HGA_GFX_PORT);
+	outb_p(0x00, HGA_STATUS_PORT);
+
+	write_hga_b(0x61, 0x00);	/* horizontal total */
+	write_hga_b(0x50, 0x01);	/* horizontal displayed */
+	write_hga_b(0x52, 0x02);	/* horizontal sync pos */
+	write_hga_b(0x0f, 0x03);	/* horizontal sync width */
+
+	write_hga_b(0x19, 0x04);	/* vertical total */
+	write_hga_b(0x06, 0x05);	/* vertical total adjust */
+	write_hga_b(0x19, 0x06);	/* vertical displayed */
+	write_hga_b(0x19, 0x07);	/* vertical sync pos */
+
+	write_hga_b(0x02, 0x08);	/* interlace mode */
+	write_hga_b(0x0d, 0x09);	/* maximum scanline */
+	write_hga_b(0x0c, 0x0a);	/* cursor start */
+	write_hga_b(0x0d, 0x0b);	/* cursor end */
+
+	write_hga_w(0x0000, 0x0c);	/* start address */
+	write_hga_w(0x0000, 0x0e);	/* cursor location */
+
+	hga_mode = HGA_TXT;
+}
+
+static void hga_gfx_mode(void)
+{
+	outb_p(0x00, HGA_STATUS_PORT);
+	outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT);
+	outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
+
+	write_hga_b(0x35, 0x00);	/* horizontal total */
+	write_hga_b(0x2d, 0x01);	/* horizontal displayed */
+	write_hga_b(0x2e, 0x02);	/* horizontal sync pos */
+	write_hga_b(0x07, 0x03);	/* horizontal sync width */
+
+	write_hga_b(0x5b, 0x04);	/* vertical total */
+	write_hga_b(0x02, 0x05);	/* vertical total adjust */
+	write_hga_b(0x57, 0x06);	/* vertical displayed */
+	write_hga_b(0x57, 0x07);	/* vertical sync pos */
+
+	write_hga_b(0x02, 0x08);	/* interlace mode */
+	write_hga_b(0x03, 0x09);	/* maximum scanline */
+	write_hga_b(0x00, 0x0a);	/* cursor start */
+	write_hga_b(0x00, 0x0b);	/* cursor end */
+
+	write_hga_w(0x0000, 0x0c);	/* start address */
+	write_hga_w(0x0000, 0x0e);	/* cursor location */
+
+	hga_mode = HGA_GFX;
+}
+
+#ifdef MODULE
+static void hga_show_logo(void)
+{
+	int x, y;
+	char *dest = (char *)hga_vram_base;
+	char *logo = linux_logo_bw;
+	for (y = 134; y < 134 + 80 ; y++) /* this needs some cleanup */
+		for (x = 0; x < 10 ; x++)
+			*(dest + (y%4)*8192 + (y>>2)*90 + x + 40) = ~*(logo++);
+}
+#endif /* MODULE */	
+
+static void hga_pan(unsigned int xoffset, unsigned int yoffset)
+{
+	unsigned int base;
+	base = (yoffset / 8) * 90 + xoffset;
+	write_hga_w(base, 0x0c);	/* start address */
+	DPRINTK("hga_pan: base:%d\n", base);
+}
+
+static int hga_card_detect(void)
+{
+	int count=0;
+	u16 *p, p_save;
+	u16 *q, q_save;
+
+	hga_vram_base = VGA_MAP_MEM(0xb0000);
+	hga_vram_len  = 0x08000;
+
+	if (!request_mem_region(hga_vram_base, hga_vram_len, "hgafb")) {
+		printk(KERN_ERR "hgafb: cannot reserve video memory at 0x%lX\n",
+				hga_vram_base);
+		return 0;
+	}
+	if (request_region(0x3b0, 12, "hgafb"))
+		release_io_ports = 1;
+	if (request_region(0x3bf, 1, "hgafb"))
+		release_io_port = 1;
+
+	/* do a memory check */
+
+	p = (u16 *) hga_vram_base;
+	q = (u16 *) (hga_vram_base + 0x01000);
+
+	p_save = scr_readw(p); q_save = scr_readw(q);
+
+	scr_writew(0xaa55, p); if (scr_readw(p) == 0xaa55) count++;
+	scr_writew(0x55aa, p); if (scr_readw(p) == 0x55aa) count++;
+	scr_writew(p_save, p);
+
+	if (count != 2) {
+		return 0;
+	}
+
+	/* Ok, there is definitely a card registering at the correct
+	 * memory location, so now we do an I/O port test.
+	 */
+	
+	if (!test_hga_b(0x66, 0x0f)) {	    /* cursor low register */
+		return 0;
+	}
+	if (!test_hga_b(0x99, 0x0f)) {     /* cursor low register */
+		return 0;
+	}
+
+	/* See if the card is a Hercules, by checking whether the vsync
+	 * bit of the status register is changing.  This test lasts for
+	 * approximately 1/10th of a second.
+	 */
+	
+	p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
+
+	for (count=0; count < 50000 && p_save == q_save; count++) {
+		q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
+		udelay(2);
+	}
+
+	if (p_save != q_save) {
+		switch (inb_p(HGA_STATUS_PORT) & 0x70) {
+			case 0x10:
+				hga_type = TYPE_HERCPLUS;
+				hga_type_name = "HerculesPlus";
+				break;
+			case 0x50:
+				hga_type = TYPE_HERCCOLOR;
+				hga_type_name = "HerculesColor";
+				break;
+			default:
+				hga_type = TYPE_HERC;
+				hga_type_name = "Hercules";
+				break;
+		}
+	}
+	return 1;
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * dispsw functions
+ *
+ * ------------------------------------------------------------------------- */
+
+
+	/*
+	 *  Open/Release the frame buffer device
+	 */
+
+static int hgafb_open(struct fb_info *info, int user)
+{
+	/* Nothing, only a usage count for the moment */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int hgafb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+	/*
+	 * Get the Fixed Part of the Display
+	 */
+
+int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_get_fix: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
+
+	*fix = info->fix;
+	return 0;
+}
+
+
+	/*
+	 *  Get the User Defined Part of the Display
+	 */
+
+int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_get_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
+
+	*var = info->var;
+	return 0;
+}
+
+	/*
+	 * Set the User Defined Part of the Display
+	 * This is the most mystical function (at least for me).
+	 * What is the exact specification of xxx_set_var?
+	 * Should it handle xoffset, yoffset? Should it do pannig?
+	 * What does vmode mean?
+	 */
+
+int hga_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_set_var: con:%d, activate:%x, info:0x%x, fb_info:%x\n", con, var->activate, (unsigned)info, (unsigned)&fb_info);
+	
+	if (var->xres != 720 ||	var->yres != 348 ||
+	    var->xres_virtual != 720 ||
+	    var->yres_virtual < 348 || var->yres_virtual > 348 + 16 ||
+	    var->bits_per_pixel != 1 || var->grayscale != 0) {
+		return -EINVAL;
+	}
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		info->var = *var;
+		if (info->changevar) 
+			(*info->changevar)(con);
+	}
+	return 0;
+}
+
+
+	/*
+	 *  Get the Colormap
+	 */
+
+static int hga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			 u_int *transp, struct fb_info *info)
+{
+	if (regno == 0) {
+		*red = *green = *blue = 0x0000;
+		*transp = 0;
+	} else if (regno == 1) {
+		*red = *green = *blue = 0xaaaa;
+		*transp = 0;
+	} else
+		return 1;
+	return 0;
+}
+
+int hga_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                 struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_get_cmap: con:%d\n", con);
+	return fb_get_cmap(cmap, kspc, hga_getcolreg, info);
+}
+	
+	/*
+	 * Set the Colormap
+	 */
+
+static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info)
+{
+	if (regno > 1)
+		return 1;
+	return 0;
+}
+
+int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                 struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_set_cmap: con:%d\n", con);
+	return fb_set_cmap(cmap, kspc, hga_setcolreg, info);
+}
+
+	/*
+	 *  Pan or Wrap the Display
+	 *
+	 *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+	 */
+
+int hga_pan_display(struct fb_var_screeninfo *var, int con,
+                    struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("pan_disp: con:%d, wrap:%d, xoff:%d, yoff:%d\n", con, var->vmode & FB_VMODE_YWRAP, var->xoffset, var->yoffset);
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0 || 
+		    var->yoffset >= info->var.yres_virtual ||
+		    var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset + var->xres > info->var.xres_virtual
+		 || var->yoffset + var->yres > info->var.yres_virtual
+		 || var->yoffset % 8)
+			return -EINVAL;
+	}
+
+	hga_pan(var->xoffset, var->yoffset);
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+    
+	/*
+	 *  Frame Buffer Specific ioctls
+	 */
+
+int hga_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+              unsigned long arg, int con, struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_ioctl: con:%d\n", con);
+	return -EINVAL;
+}
+
+
+	
+	
+static struct fb_ops hgafb_ops = {
+	hgafb_open, hgafb_release, hga_get_fix, hga_get_var, hga_set_var,
+	hga_get_cmap, hga_set_cmap, hga_pan_display, hga_ioctl
+};
+		
+
+/* ------------------------------------------------------------------------- *
+ *
+ * Functions in fb_info
+ * 
+ * ------------------------------------------------------------------------- */
+
+static int hgafbcon_switch(int con, struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hgafbcon_switch: currcon:%d, con:%d, info:%x, fb_info:%x\n", currcon, con, (unsigned)info, (unsigned)&fb_info);
+
+	/* Save the colormap and video mode */
+#if 0	/* Not necessary in hgafb, we use fixed colormap */
+	fb_copy_cmap(&info->cmap, &fb_display[currcon].cmap, 0);
+#endif
+
+	if (currcon != -1) /* this check is absolute necessary! */
+		memcpy(&fb_display[currcon].var, &info->var,
+				sizeof(struct fb_var_screeninfo));
+
+	/* Install a new colormap and change the video mode. By default fbcon
+	 * sets all the colormaps and video modes to the default values at
+	 * bootup.
+	 */
+#if 0
+	fb_copy_cmap(&fb_display[con].cmap, &info->cmap, 0);
+	fb_set_cmap(&info->cmap, 1, hga_setcolreg, info);
+#endif
+
+	memcpy(&info->var, &fb_display[con].var,
+			sizeof(struct fb_var_screeninfo));
+	/* hga_set_var(&info->var, con, &fb_info); is it necessary? */
+	currcon = con;
+
+	/* Hack to work correctly with XF86_Mono */
+	hga_gfx_mode();
+	return 0;
+}
+
+static int hgafbcon_updatevar(int con, struct fb_info *info)
+{
+	CHKINFO(-EINVAL);
+	DPRINTK("hga_update_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
+	return (con < 0) ? -EINVAL : hga_pan_display(&fb_display[con].var, con, info);
+}
+
+static void hgafbcon_blank(int blank_mode, struct fb_info *info)
+{
+	/*
+	 *  Blank the screen if blank_mode != 0, else unblank. 
+	 *  Implements VESA suspend and powerdown modes on hardware 
+	 *  that supports disabling hsync/vsync:
+	 *    blank_mode == 2: suspend vsync
+	 *    blank_mode == 3: suspend hsync
+	 *    blank_mode == 4: powerdown
+	 */
+
+	CHKINFO( );
+	DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info);
+
+	if (blank_mode) {
+		outb_p(0x00, HGA_MODE_PORT);	/* disable video */
+	} else {
+		outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
+	}
+}
+
+
+/* ------------------------------------------------------------------------- */
+    
+	/*
+	 *  Initialization
+	 */
+
+int __init hgafb_init(void)
+{
+	if (! hga_card_detect()) {
+		printk(KERN_ERR "hgafb: HGA card not detected.\n");
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
+		hga_type_name, hga_vram_len/1024);
+
+	hga_gfx_mode();
+	hga_clear_screen();
+#ifdef MODULE
+	if (!nologo) hga_show_logo();
+#endif /* MODULE */
+
+	hga_fix.smem_start = hga_vram_base;
+	hga_fix.smem_len = hga_vram_len;
+
+	disp.var = hga_default_var;
+/*	disp.cmap = ???; */
+	disp.screen_base = (char*)hga_fix.smem_start;
+	disp.visual = hga_fix.visual;
+	disp.type = hga_fix.type;
+	disp.type_aux = hga_fix.type_aux;
+	disp.ypanstep = hga_fix.ypanstep;
+	disp.ywrapstep = hga_fix.ywrapstep;
+	disp.line_length = hga_fix.line_length;
+	disp.can_soft_blank = 1;
+	disp.inverse = 0;
+	disp.dispsw = &fbcon_hga;
+	disp.dispsw_data = NULL;
+
+	disp.scrollmode = SCROLL_YREDRAW;
+	
+	strcpy (fb_info.modename, hga_fix.id);
+	fb_info.node = -1;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+/*	fb_info.open = ??? */
+	fb_info.var = hga_default_var;
+	fb_info.fix = hga_fix;
+	fb_info.monspecs.hfmin = 0;
+	fb_info.monspecs.hfmax = 0;
+	fb_info.monspecs.vfmin = 10000;
+	fb_info.monspecs.vfmax = 10000;
+	fb_info.monspecs.dpms = 0;
+	fb_info.fbops = &hgafb_ops;
+	fb_info.screen_base = (char *)hga_fix.smem_start;
+	fb_info.disp = &disp;
+/*	fb_info.display_fg = ??? */
+/*	fb_info.fontname initialized later */
+	fb_info.changevar = NULL;
+	fb_info.switch_con = hgafbcon_switch;
+	fb_info.updatevar = hgafbcon_updatevar;
+	fb_info.blank = hgafbcon_blank;
+	fb_info.pseudo_palette = NULL; /* ??? */
+	fb_info.par = NULL;
+
+        if (register_framebuffer(&fb_info) < 0)
+                return -EINVAL;
+
+        printk(KERN_INFO "fb%d: %s frame buffer device\n",
+               GET_FB_IDX(fb_info.node), fb_info.modename);
+	
+	return 0;
+}
+
+	/*
+	 *  Setup
+	 */
+
+#ifndef MODULE
+int __init hgafb_setup(char *options)
+{
+	/* 
+	 * Parse user speficied options
+	 * `video=hga:font:VGA8x16' or
+	 * `video=hga:font:SUN8x16' recommended
+	 * Other supported fonts: VGA8x8, Acorn8x8, PEARL8x8
+	 * More different fonts can be used with the `setfont' utility.
+	 */
+
+	char *this_opt;
+
+	fb_info.fontname[0] = '\0';
+
+	if (!options || !*options)
+		return 0;
+
+	for (this_opt = strtok(options, ","); this_opt;
+			this_opt = strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "font:", 5))
+			strcpy(fb_info.fontname, this_opt+5);
+	}
+	return 0;
+}
+#endif /* !MODULE */
+
+
+	/*
+	 * Cleanup
+	 */
+
+#ifdef MODULE
+static void hgafb_cleanup(struct fb_info *info)
+{
+	hga_txt_mode();
+	hga_clear_screen();
+	unregister_framebuffer(info);
+	if (release_io_ports) release_region(0x3b0, 12);
+	if (release_io_port) release_region(0x3bf, 1);
+	release_mem_region(hga_vram_base, hga_vram_len);
+}
+#endif /* MODULE */
+
+
+
+/* -------------------------------------------------------------------------
+ *
+ *  Modularization
+ *
+ * ------------------------------------------------------------------------- */
+
+#ifdef MODULE
+int init_module(void)
+{
+	if (font)
+		strncpy(fb_info.fontname, font, sizeof(fb_info.fontname)-1);
+	else
+		fb_info.fontname[0] = '\0';
+
+	return hgafb_init();
+}
+
+void cleanup_module(void)
+{
+	hgafb_cleanup(&fb_info);
+}
+
+MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)");
+MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor");
+
+MODULE_PARM(font, "s");
+MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (VGA8x8, VGA8x16, SUN8x16, Acorn8x8, PEARL8x8) (default=none)");
+MODULE_PARM(nologo, "i");
+MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)");
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.49/linux/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c
--- v2.3.49/linux/drivers/video/riva/fbdev.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/riva/fbdev.c	Fri Mar  3 12:54:45 2000
@@ -517,8 +517,8 @@
 	rinfo->riva.Architecture = rci->arch_rev;
 
 	rinfo->pd = pd;
-	rinfo->base0_region_size = pci_resource_start (pd, 0);
-	rinfo->base1_region_size = pci_resource_start (pd, 1);
+	rinfo->base0_region_size = pci_resource_len (pd, 0);
+	rinfo->base1_region_size = pci_resource_len (pd, 1);
 
 	assert (rinfo->base0_region_size >= 0x00800000);	/* from GGI */
 	assert (rinfo->base0_region_size >= 0x01000000);	/* from GGI */
diff -u --recursive --new-file v2.3.49/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.3.49/linux/drivers/video/vesafb.c	Thu Mar  2 14:36:23 2000
+++ linux/drivers/video/vesafb.c	Sat Mar  4 20:03:50 2000
@@ -648,8 +648,12 @@
 	 * region already (FIXME) */
 	request_region(0x3c0, 32, "vesafb");
 
-	if (mtrr)
-		mtrr_add(video_base, video_size, MTRR_TYPE_WRCOMB, 1);
+	if (mtrr) {
+		int temp_size = video_size;
+		while (mtrr_add(video_base, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
+			temp_size >>= 1;
+		}
+	}
 	
 	strcpy(fb_info.modename, "VESA VGA");
 	fb_info.changevar = NULL;
diff -u --recursive --new-file v2.3.49/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.3.49/linux/drivers/video/vgacon.c	Sat Feb 26 22:31:51 2000
+++ linux/drivers/video/vgacon.c	Mon Mar  6 15:55:51 2000
@@ -94,6 +94,8 @@
 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
 static unsigned long vgacon_uni_pagedir[2];
 
+void clear_status_line( void );
+
 
 /* Description of the hardware situation */
 static unsigned long   vga_vram_base;		/* Base of video memory */
@@ -349,6 +351,7 @@
 static inline void vga_set_mem_top(struct vc_data *c)
 {
 	write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
+	clear_status_line();
 }
 
 static void vgacon_deinit(struct vc_data *c)
@@ -1057,3 +1060,80 @@
 	vgacon_build_attr,
 	vgacon_invert_region
 };
+
+
+int inited = 0;
+
+void
+clear_status_line( void )
+{
+#if CONFIG_COMMENT_INT==3
+        u16 *org;
+        int i;
+        int currcons = fg_console;
+	struct vc_data *c = vc_cons[fg_console].d;
+	if (!inited) return;
+        if (vga_is_gfx) return;
+	if (c->vc_origin != c->vc_visible_origin) return;
+        org = screen_pos( fg_console, video_num_lines*video_num_columns, 1 );
+        for (i=0; i<video_num_columns; i++)
+                scr_writew( (0x0f << 8) + ' ', org++ );
+#endif
+}
+
+#if CONFIG_COMMENT_INT==3
+void
+paint_status_line( int timer )
+{
+	u16 *org;
+	int i,j;
+	int currcons = fg_console;
+	struct vc_data *c = vc_cons[fg_console].d;
+
+	if (!inited) return;
+	if (vga_is_gfx)		/* We don't play origin tricks in graphic modes */
+		return;
+	if (c->vc_origin != c->vc_visible_origin) return;
+
+	org = screen_pos( fg_console, video_num_lines*video_num_columns, 1 );
+
+	/* Are we busy? */
+	{
+		i = current->pid;
+		j = 0;
+		if (i)
+			j = (i>16) ? ((current->priority < DEF_PRIORITY) ? 0xA0:0xE0) : 0xC0;
+		scr_writew( (j<<8) + ' ', org++ );
+
+#if 0
+		org++;
+
+#define DISP( x ) scr_writew(  (((i&x) ? 0x90:0) << 8) + ' ', org++ );
+		DISP( 0x80 );
+		DISP( 0x40 );
+		DISP( 0x20 );
+		DISP( 0x10 );
+		DISP( 0x08 );
+		DISP( 0x04 );
+		DISP( 0x02 );
+		DISP( 0x01 );
+#endif
+	}
+
+	if (!timer) return;
+
+	org++;
+	/* Serial? */
+	{
+		j = (ledflags & 0x10) ? 0x90 : 0x00;
+		scr_writew( (j<<8) + 'S', org++ );
+	}
+
+	org++;
+	/* NE2000? */
+	{
+		j = (ledflags & 0x20) ? 0x90 : 0x00;
+		scr_writew( (j<<8) + 'N', org++ );
+	}
+}
+#endif
diff -u --recursive --new-file v2.3.49/linux/drivers/zorro/Makefile linux/drivers/zorro/Makefile
--- v2.3.49/linux/drivers/zorro/Makefile	Fri Jan 28 15:09:08 2000
+++ linux/drivers/zorro/Makefile	Tue Mar  7 10:52:41 2000
@@ -9,24 +9,17 @@
 # parent makefile.
 #
 
-SUB_DIRS     :=
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
 L_TARGET := zorro.a
 
-# Nasty trick as nobody references zorrosyms.o, but we still want it linked.
-ifeq ($(CONFIG_MODULES),y)
-O_TARGET = zorro_syms.o
-OX_OBJS  = zorrosyms.o
-O_OBJS   = zorro.o names.o
-L_OBJS   := zorro_syms.o
-else
-L_OBJS   := zorro.o names.o
-endif
+# Nasty trick as we need to link files with no references from the outside.
+O_TARGET := zorro_core.o
+L_OBJS   := zorro_core.o
+OX_OBJS   := zorro.o
 
 ifdef CONFIG_PROC_FS
-L_OBJS   += proc.o
+O_OBJS   += proc.o
 endif
+
+L_OBJS   += names.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.49/linux/drivers/zorro/proc.c linux/drivers/zorro/proc.c
--- v2.3.49/linux/drivers/zorro/proc.c	Sat Feb 26 22:31:51 2000
+++ linux/drivers/zorro/proc.c	Tue Mar  7 10:52:41 2000
@@ -120,14 +120,18 @@
 	return 0;
 }
 
-void __init zorro_proc_init(void)
+static int __init zorro_proc_init(void)
 {
 	u_int slot;
 
-	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
-		return;
-	proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus);
-	create_proc_info_entry("devices", 0, proc_bus_zorro_dir, get_zorro_dev_info);
-	for (slot = 0; slot < zorro_num_autocon; slot++)
-	    zorro_proc_attach_device(slot);
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
+		proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus);
+		create_proc_info_entry("devices", 0, proc_bus_zorro_dir,
+				       get_zorro_dev_info);
+		for (slot = 0; slot < zorro_num_autocon; slot++)
+			zorro_proc_attach_device(slot);
+	}
+	return 0;
 }
+
+__initcall(zorro_proc_init);
diff -u --recursive --new-file v2.3.49/linux/drivers/zorro/zorro.c linux/drivers/zorro/zorro.c
--- v2.3.49/linux/drivers/zorro/zorro.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/zorro/zorro.c	Tue Mar  7 10:52:41 2000
@@ -10,7 +10,7 @@
  *    for more details.
  */
 
-#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -75,6 +75,8 @@
      *  Possible uses:
      *      - z2ram device
      *      - SCSI DMA bounce buffers
+     *
+     *  FIXME: use the normal resource management
      */
 
 u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 };
@@ -151,8 +153,8 @@
 	if (m68k_memory[i].addr < 16*1024*1024)
 	    mark_region(m68k_memory[i].addr,
 			m68k_memory[i].addr+m68k_memory[i].size, 0);
-
-#ifdef CONFIG_PROC_FS
-    zorro_proc_init();
-#endif
 }
+
+
+EXPORT_SYMBOL(zorro_find_device);
+EXPORT_SYMBOL(zorro_unused_z2ram);
diff -u --recursive --new-file v2.3.49/linux/drivers/zorro/zorrosyms.c linux/drivers/zorro/zorrosyms.c
--- v2.3.49/linux/drivers/zorro/zorrosyms.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/zorro/zorrosyms.c	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/*
- *	$Id: zorrosyms.c,v 1.1.2.1 1998/06/07 23:21:02 geert Exp $
- *
- *	Zorro Bus Services -- Exported Symbols
- *
- *	Copyright (C) 1998-2000 Geert Uytterhoeven
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/zorro.h>
-
-    /* Board configuration */
-
-EXPORT_SYMBOL(zorro_find_device);
-
-    /* Z2 memory */
-
-EXPORT_SYMBOL(zorro_unused_z2ram);
-
diff -u --recursive --new-file v2.3.49/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
--- v2.3.49/linux/fs/adfs/dir.c	Sat Feb 26 22:31:51 2000
+++ linux/fs/adfs/dir.c	Mon Mar  6 15:49:21 2000
@@ -256,12 +256,8 @@
 }
 
 struct dentry_operations adfs_dentry_operations = {
-	NULL,		/* revalidate */
-	adfs_hash,
-	adfs_compare,
-	NULL,		/* delete  = called by dput */
-	NULL,		/* release - called by d_free */
-	NULL		/* iput    - called by dentry_iput */
+	d_hash:		adfs_hash,
+	d_compare:	adfs_compare,
 };
 
 struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry)
diff -u --recursive --new-file v2.3.49/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.3.49/linux/fs/affs/namei.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/affs/namei.c	Mon Mar  6 15:49:21 2000
@@ -44,10 +44,8 @@
 static int	 affs_hash_dentry(struct dentry *, struct qstr *);
 static int       affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 struct dentry_operations affs_dentry_operations = {
-	NULL,			/* d_validate	*/
-	affs_hash_dentry,	/* d_hash	*/
-	affs_compare_dentry,	/* d_compare	*/
-	NULL			/* d_delete	*/
+	d_hash:		affs_hash_dentry,
+	d_compare:	affs_compare_dentry,
 };
 
 /*
diff -u --recursive --new-file v2.3.49/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.3.49/linux/fs/autofs/root.c	Sat Feb 26 22:31:51 2000
+++ linux/fs/autofs/root.c	Mon Mar  6 15:49:21 2000
@@ -174,9 +174,7 @@
 }
 
 static struct dentry_operations autofs_dentry_operations = {
-	autofs_revalidate,	/* d_revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
+	d_revalidate:	autofs_revalidate,
 };
 
 static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry)
diff -u --recursive --new-file v2.3.49/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.49/linux/fs/binfmt_elf.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/binfmt_elf.c	Tue Mar  7 11:10:13 2000
@@ -707,7 +707,9 @@
 		__MOD_INC_USE_COUNT(current->binfmt->module);
 
 #ifndef VM_STACK_FLAGS
+	lock_kernel();
 	current->executable = dget(bprm->dentry);
+	unlock_kernel();
 #endif
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
diff -u --recursive --new-file v2.3.49/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c
--- v2.3.49/linux/fs/binfmt_em86.c	Sat Feb 26 22:31:51 2000
+++ linux/fs/binfmt_em86.c	Tue Mar  7 11:10:13 2000
@@ -42,7 +42,9 @@
 	}
 
 	bprm->sh_bang++;	/* Well, the bang-shell is implicit... */
+	lock_kernel();
 	dput(bprm->dentry);
+	unlock_kernel();
 	bprm->dentry = NULL;
 
 	/* Unlike in the script case, we don't have to do any hairy
@@ -78,7 +80,9 @@
 	 * Note that we use open_namei() as the name is now in kernel
 	 * space, and we don't need to copy it.
 	 */
+	lock_kernel();
 	dentry = open_namei(interp, 0, 0);
+	unlock_kernel();
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
diff -u --recursive --new-file v2.3.49/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.3.49/linux/fs/block_dev.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/block_dev.c	Thu Mar  2 21:55:53 2000
@@ -630,7 +630,7 @@
 	/* syncing will go here */
 	if (kind == BDEV_FILE || kind == BDEV_FS)
 		fsync_dev(rdev);
-	if (atomic_dec_and_test(&bdev->bd_openers) && MAJOR(rdev) != RAMDISK_MAJOR) {
+	if (atomic_dec_and_test(&bdev->bd_openers)) {
 		/* invalidating buffers will go here */
 		invalidate_buffers(rdev);
 	}
diff -u --recursive --new-file v2.3.49/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.49/linux/fs/buffer.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/buffer.c	Tue Mar  7 11:10:57 2000
@@ -2474,6 +2474,7 @@
  */
 int bdflush(void * unused) 
 {
+	struct task_struct *tsk = current;
 	int flushed;
 	/*
 	 *	We have a bare-bones task_struct, and really should fill
@@ -2481,17 +2482,17 @@
 	 *	display semi-sane things. Not real crucial though...  
 	 */
 
-	current->session = 1;
-	current->pgrp = 1;
-	sprintf(current->comm, "kflushd");
-	bdflush_tsk = current;
+	tsk->session = 1;
+	tsk->pgrp = 1;
+	strcpy(tsk->comm, "kflushd");
+	bdflush_tsk = tsk;
 
 	/* avoid getting signals */
-	spin_lock_irq(&current->sigmask_lock);
-	flush_signals(current);
-	sigfillset(&current->blocked);
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_lock_irq(&tsk->sigmask_lock);
+	flush_signals(tsk);
+	sigfillset(&tsk->blocked);
+	recalc_sigpending(tsk);
+	spin_unlock_irq(&tsk->sigmask_lock);
 
 	for (;;) {
 		CHECK_EMERGENCY_SYNC
diff -u --recursive --new-file v2.3.49/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.3.49/linux/fs/coda/dir.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/coda/dir.c	Mon Mar  6 15:49:21 2000
@@ -57,10 +57,8 @@
 
 struct dentry_operations coda_dentry_operations =
 {
-	coda_dentry_revalidate, /* revalidate */
-	NULL, /* hash */
-	NULL, /* compare */
-	coda_dentry_delete /* delete */
+	d_revalidate:	coda_dentry_revalidate,
+	d_delete:	coda_dentry_delete,
 };
 
 struct inode_operations coda_dir_inode_operations =
@@ -541,9 +539,7 @@
                 result = coda_venus_readdir(&open_file, dirent, filldir);
         } else {
                 /* potemkin case: we are handed a directory inode */
-		down(&cnp->c_ovp->i_sem);
-                result = open_file.f_op->readdir(&open_file, dirent, filldir);
-		up(&cnp->c_ovp->i_sem);
+                result = vfs_readdir(&open_file, filldir, dirent);
         }
 	coda_restore_codafile(inode, file, cnp->c_ovp, &open_file);
         EXIT;
diff -u --recursive --new-file v2.3.49/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.3.49/linux/fs/devfs/base.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/devfs/base.c	Tue Mar  7 11:07:42 2000
@@ -426,6 +426,12 @@
 	       Removed <devfs_fill_file>.
 	       Work sponsored by SGI.
   v0.92
+    20000306   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added DEVFS_FL_NO_PERSISTENCE flag.
+	       Removed unnecessary call to <update_devfs_inode_from_entry> in
+	       <devfs_readdir>.
+	       Work sponsored by SGI.
+  v0.93
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -460,7 +466,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.92 (20000203)"
+#define DEVFS_VERSION            "0.93 (20000306)"
 
 #ifndef DEVFS_NAME
 #  define DEVFS_NAME "devfs"
@@ -601,6 +607,7 @@
     unsigned char registered:1;
     unsigned char show_unreg:1;
     unsigned char hide:1;
+    unsigned char no_persistence:1;
     char name[1];            /*  This is just a dummy: the allocated array is
 				 bigger. This is NULL-terminated  */
 };
@@ -1240,6 +1247,7 @@
     de->show_unreg = ( (boot_options & OPTION_SHOW)
 			|| (flags & DEVFS_FL_SHOW_UNREG) ) ? TRUE : FALSE;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
+    de->no_persistence = (flags & DEVFS_FL_NO_PERSISTENCE) ? TRUE : FALSE;
     devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
     return de;
 }   /*  End Function devfs_register  */
@@ -1983,24 +1991,17 @@
     else
     {
 	if (di->de->u.fcb.auto_owner)
-	{
-	    mode_t mode = di->de->mode;
-	    
-	    di->mode = (mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
-	}
-	else
-	{
-	    di->mode = di->de->mode;
-	}
+	    di->mode = (di->de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO;
+	else di->mode = di->de->mode;
 	di->uid = di->de->u.fcb.default_uid;
 	di->gid = di->de->u.fcb.default_gid;
     }
 }   /*  End Function update_devfs_inode_from_entry  */
 
-static struct devfs_inode *create_devfs_inode (struct devfs_entry *entry,
+static struct devfs_inode *create_devfs_inode (struct devfs_entry *de,
 					       struct fs_info *fs_info)
 /*  [SUMMARY] Create a devfs inode entry.
-    <entry> The devfs entry to associate the new inode with.
+    <de> The devfs entry to associate the new inode with.
     <fs_info> The FS info.
     [RETURNS] A pointer to the devfs inode on success, else NULL.
 */
@@ -2032,12 +2033,12 @@
     di->nlink = 1;
     fs_info->table[fs_info->num_inodes] = di;
     ++fs_info->num_inodes;
-    di->de = entry;
+    di->de = de;
     di->fs_info = fs_info;
-    di->prev = entry->last_inode;
-    if (entry->first_inode == NULL) entry->first_inode = di;
-    else entry->last_inode->next = di;
-    entry->last_inode = di;
+    di->prev = de->last_inode;
+    if (de->first_inode == NULL) de->first_inode = di;
+    else de->last_inode->next = di;
+    de->last_inode = di;
     update_devfs_inode_from_entry (di);
 #ifdef CONFIG_DEVFS_DEBUG
     if (devfs_debug & DEBUG_I_CREATE)
@@ -2183,8 +2184,9 @@
 
 /*  Superblock operations follow  */
 
-extern struct inode_operations devfs_iops;
+static struct inode_operations devfs_iops;
 static struct file_operations devfs_fops;
+static struct inode_operations devfs_symlink_iops;
 
 static void devfs_read_inode (struct inode *inode)
 {
@@ -2206,22 +2208,29 @@
     inode->i_blocks = 0;
     inode->i_blksize = 1024;
     inode->i_op = &devfs_iops;
-    inode->i_fop = &devfs_fops;
     inode->i_rdev = NODEV;
-    if ( S_ISCHR (di->mode) )
+    if ( S_ISCHR (di->mode) ) {
 	inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major,
 			       di->de->u.fcb.u.device.minor);
-    else if ( S_ISBLK (di->mode) )
-    {
+	inode->i_fop = &devfs_fops;
+    } else if ( S_ISBLK (di->mode) ) {
 	inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major,
 			       di->de->u.fcb.u.device.minor);
 	inode->i_bdev = bdget (inode->i_rdev);
 	if (inode->i_bdev) inode->i_bdev->bd_op = di->de->u.fcb.ops;
 	else printk ("%s: read_inode(%d): no block device from bdget()\n",
 		     DEVFS_NAME, (int) inode->i_ino);
+	inode->i_fop = &devfs_fops;
+    } else if ( S_ISFIFO (di->mode) ) {
+	inode->i_fop = &def_fifo_fops;
+    } else if ( S_ISREG (di->mode) ) {
+	inode->i_size = di->de->u.fcb.u.file.size;
+	inode->i_fop = &devfs_fops;
+    } else if (S_ISLNK(di->mode)) {
+	inode->i_op = &devfs_symlink_iops;
+    } else {
+	inode->i_fop = &devfs_fops;
     }
-    else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops;
-    else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size;
     inode->i_mode = di->mode;
     inode->i_uid = di->uid;
     inode->i_gid = di->gid;
@@ -2438,11 +2447,10 @@
 	    if (di == NULL)
 	    {
 		if (fs_info->require_explicit) continue;
-		/*  Have to create the inode right now  */
+		/*  Have to create the inode right now to get the inum  */
 		di = create_devfs_inode (de, fs_info);
 		if (di == NULL) return -ENOMEM;
 	    }
-	    else if (di->ctime == 0) update_devfs_inode_from_entry (di);
 	    err = (*filldir) (dirent, de->name, de->namelen,
 			      file->f_pos, di->ino);
 	    if (err == -EINVAL) break;
@@ -2659,6 +2667,7 @@
 	    /*  Create an inode, now that the driver information is available
 	     */
 	    if (di == NULL) di = create_devfs_inode (de, fs_info);
+	    else if (de->no_persistence) update_devfs_inode_from_entry (di);
 	    else if (di->ctime == 0) update_devfs_inode_from_entry (di);
 	    else di->mode = (de->mode & ~S_IALLUGO) | (di->mode & S_IALLUGO);
 	    if (di == NULL) return 1;
@@ -2784,6 +2793,7 @@
     }
     /*  Create an inode, now that the driver information is available  */
     if (di == NULL) di = create_devfs_inode (de, fs_info);
+    else if (de->no_persistence) update_devfs_inode_from_entry (di);
     else if (di->ctime == 0) update_devfs_inode_from_entry (di);
     else di->mode = (de->mode & ~S_IALLUGO) | (di->mode & S_IALLUGO);
     if (di == NULL) return ERR_PTR (-ENOMEM);
@@ -3079,49 +3089,24 @@
 
 static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen)
 {
-    struct inode *inode = dentry->d_inode;
-    struct devfs_inode *di;
+	struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode);
+	char *name = ERR_PTR(-ENOENT);
 
-    if ( !inode || !S_ISLNK (inode->i_mode) ) return -EINVAL;
-    di = get_devfs_inode_from_vfs_inode (inode);
-    if (di == NULL) return -ENOENT;
-    if (!di->de->registered) return -ENOENT;
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_RLINK)
-	printk ("%s: readlink(): dentry: %p\n", DEVFS_NAME, dentry);
-#endif
-    if (buflen > di->de->u.symlink.length + 1)
-	buflen = di->de->u.symlink.length + 1;
-    if (copy_to_user (buffer, di->de->u.symlink.linkname, buflen) == 0)
-	return buflen;
-    return -EFAULT;
+	if (di && di->de->registered)
+		name = di->de->u.symlink.linkname;
+	return vfs_readlink(dentry, buffer, buflen, name);
 }   /*  End Function devfs_readlink  */
 
 static struct dentry *devfs_follow_link (struct dentry *dentry,
 					 struct dentry *base,
 					 unsigned int follow)
 {
-    struct inode *inode = dentry->d_inode;
-    struct devfs_inode *di;
+	struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode);
+	char *name = ERR_PTR(-ENOENT);
 
-    if ( !inode || !S_ISLNK (inode->i_mode) )
-    {
-	dget (dentry);
-	dput (base);
-	return dentry;
-    }
-#ifdef CONFIG_DEVFS_DEBUG
-    if (devfs_debug & DEBUG_I_FLINK)
-	printk ("%s: follow_link(): dentry: %p\n", DEVFS_NAME, dentry);
-#endif
-    di = get_devfs_inode_from_vfs_inode (inode);
-    if ( (di == NULL) || !di->de->registered )
-    {
-	dput (base);
-	return ERR_PTR (-ENOENT);
-    }
-    base = lookup_dentry (di->de->u.symlink.linkname, base, follow);
-    return base;
+	if (di && di->de->registered)
+		name = di->de->u.symlink.linkname;
+	return vfs_follow_link(dentry, base, follow, name);
 }   /*  End Function devfs_follow_link  */
 
 static struct inode_operations devfs_iops =
@@ -3133,6 +3118,11 @@
 	mkdir:		devfs_mkdir,
 	rmdir:		devfs_rmdir,
 	mknod:		devfs_mknod,
+	setattr:	devfs_notify_change,
+};
+
+static struct inode_operations devfs_symlink_iops =
+{
 	readlink:	devfs_readlink,
 	follow_link:	devfs_follow_link,
 	setattr:	devfs_notify_change,
diff -u --recursive --new-file v2.3.49/linux/fs/devpts/root.c linux/fs/devpts/root.c
--- v2.3.49/linux/fs/devpts/root.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/devpts/root.c	Mon Mar  6 15:49:21 2000
@@ -30,9 +30,7 @@
 };
 
 static struct dentry_operations devpts_dentry_operations = {
-	devpts_revalidate,	/* d_revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
+	d_revalidate:	devpts_revalidate,
 };
 
 /*
diff -u --recursive --new-file v2.3.49/linux/fs/exec.c linux/fs/exec.c
--- v2.3.49/linux/fs/exec.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/exec.c	Tue Mar  7 11:10:13 2000
@@ -84,6 +84,7 @@
 	struct list_head * l = NULL;
 	int fd, error;
 
+	lock_kernel();
 	if (inode->i_sb)
 		l = &inode->i_sb->s_files;
 
@@ -111,6 +112,7 @@
 		fd_install(fd, f);
 		dget(dentry);
 	}
+	unlock_kernel();
 	return fd;
 
 out_filp:
@@ -120,6 +122,7 @@
 out_fd:
 	put_unused_fd(fd);
 out:
+	unlock_kernel();
 	return error;
 }
 
diff -u --recursive --new-file v2.3.49/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.3.49/linux/fs/fat/fatfs_syms.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/fat/fatfs_syms.c	Tue Mar  7 11:11:24 2000
@@ -52,6 +52,7 @@
 EXPORT_SYMBOL(fat_dir_ioctl);
 EXPORT_SYMBOL(fat_add_entries);
 EXPORT_SYMBOL(fat_dir_empty);
+EXPORT_SYMBOL(fat_truncate);
 
 int init_fat_fs(void)
 {
diff -u --recursive --new-file v2.3.49/linux/fs/fifo.c linux/fs/fifo.c
--- v2.3.49/linux/fs/fifo.c	Sat Feb 26 22:31:52 2000
+++ linux/fs/fifo.c	Sun Mar  5 09:26:52 2000
@@ -41,6 +41,7 @@
 		PIPE_BASE(*inode) = (char *) page;
 		PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
 		PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+		PIPE_WAITING_WRITERS(*inode) = PIPE_WAITING_READERS(*inode) = 0;
 	}
 
 	switch (filp->f_mode) {
diff -u --recursive --new-file v2.3.49/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c
--- v2.3.49/linux/fs/hfs/sysdep.c	Sat May  8 17:56:37 1999
+++ linux/fs/hfs/sysdep.c	Mon Mar  6 15:49:21 2000
@@ -24,12 +24,10 @@
 static void hfs_dentry_iput(struct dentry *, struct inode *);
 struct dentry_operations hfs_dentry_operations =
 {
-	hfs_revalidate_dentry,	/* d_revalidate(struct dentry *) */
-	hfs_hash_dentry,	/* d_hash */
-	hfs_compare_dentry,    	/* d_compare */
-	NULL,	                /* d_delete(struct dentry *) */
-	NULL,                   /* d_release(struct dentry *) */
-	hfs_dentry_iput         /* d_iput(struct dentry *, struct inode *) */
+	d_revalidate:	hfs_revalidate_dentry,	
+	d_hash:		hfs_hash_dentry,
+	d_compare:	hfs_compare_dentry,
+	d_iput:		hfs_dentry_iput,
 };
 
 /*
diff -u --recursive --new-file v2.3.49/linux/fs/hpfs/dentry.c linux/fs/hpfs/dentry.c
--- v2.3.49/linux/fs/hpfs/dentry.c	Sun May 16 10:27:40 1999
+++ linux/fs/hpfs/dentry.c	Mon Mar  6 15:49:21 2000
@@ -50,10 +50,8 @@
 }
 
 struct dentry_operations hpfs_dentry_operations = {
-	NULL,			/* d_validate   */
-	hpfs_hash_dentry,	/* d_hash       */
-	hpfs_compare_dentry,	/* d_compare    */
-	NULL			/* d_delete     */
+	d_hash:		hpfs_hash_dentry,
+	d_compare:	hpfs_compare_dentry,
 };
 
 void hpfs_set_dentry_operations(struct dentry *dentry)
diff -u --recursive --new-file v2.3.49/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.49/linux/fs/isofs/inode.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/isofs/inode.c	Mon Mar  6 15:49:21 2000
@@ -84,29 +84,21 @@
 
 static struct dentry_operations isofs_dentry_ops[] = {
 	{
-		NULL,			/* d_revalidate */
-		isofs_hash,
-		isofs_cmp,
-		NULL			/* d_delete */
+		d_hash:		isofs_hash,
+		d_compare:	isofs_cmp,
 	},
 	{
-		NULL,			/* d_revalidate */
-		isofs_hashi,
-		isofs_cmpi,
-		NULL			/* d_delete */
+		d_hash:		isofs_hashi,
+		d_compare:	isofs_cmpi,
 	},
 #ifdef CONFIG_JOLIET
 	{
-		NULL,			/* d_revalidate */
-		isofs_hash_ms,
-		isofs_cmp_ms,
-		NULL			/* d_delete */
+		d_hash:		isofs_hash_ms,
+		d_compare:	isofs_cmp_ms,
 	},
 	{
-		NULL,			/* d_revalidate */
-		isofs_hashi_ms,
-		isofs_cmpi_ms,
-		NULL			/* d_delete */
+		d_hash:		isofs_hashi_ms,
+		d_compare:	isofs_cmpi_ms,
 	}
 #endif
 };
diff -u --recursive --new-file v2.3.49/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.3.49/linux/fs/minix/namei.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/minix/namei.c	Mon Mar  6 15:49:21 2000
@@ -106,13 +106,9 @@
 #endif
 
 struct dentry_operations minix_dentry_operations = {
-	0,		/* revalidate */
 #ifndef NO_TRUNCATE
-	minix_hash,
-#else
-	0,
+	d_hash:		minix_hash,
 #endif
-	0		/* compare */
 };
 
 static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
diff -u --recursive --new-file v2.3.49/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.3.49/linux/fs/msdos/namei.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/msdos/namei.c	Mon Mar  6 15:49:21 2000
@@ -200,12 +200,8 @@
 
 
 static struct dentry_operations msdos_dentry_operations = {
-	NULL, 		/* d_revalidate */
-	msdos_hash,
-	msdos_cmp,
-	NULL,		/* d_delete */
-	NULL,
-	NULL
+	d_hash:		msdos_hash,
+	d_compare:	msdos_cmp,
 };
 
 /*
diff -u --recursive --new-file v2.3.49/linux/fs/namei.c linux/fs/namei.c
--- v2.3.49/linux/fs/namei.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/namei.c	Tue Mar  7 11:12:28 2000
@@ -403,10 +403,10 @@
 				if (IS_ERR(dentry))
 					break;
 			}
-		}
 
-		/* Check mountpoints.. */
-		dentry = follow_mount(dentry);
+			/* Check mountpoints.. */
+			dentry = follow_mount(dentry);
+		}
 
 		base = do_follow_link(base, dentry, flags);
 		if (IS_ERR(base))
@@ -577,6 +577,9 @@
 {
 	int error;
 
+	mode &= S_IALLUGO & ~current->fs->umask;
+	mode |= S_IFREG;
+
 	error = may_create(dir, dentry);
 	if (error)
 		goto exit_lock;
@@ -610,9 +613,6 @@
 	struct inode *inode;
 	struct dentry *dentry;
 
-	mode &= S_IALLUGO & ~current->fs->umask;
-	mode |= S_IFREG;
-
 	dentry = lookup_dentry(pathname, NULL, lookup_flags(flag));
 	if (IS_ERR(dentry))
 		return dentry;
@@ -739,14 +739,36 @@
 	return ERR_PTR(error);
 }
 
+int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+	int error = -EPERM;
+
+	mode &= ~current->fs->umask;
+
+	if (!S_ISFIFO(mode) && !capable(CAP_MKNOD))
+		goto exit_lock;
+
+	error = may_create(dir, dentry);
+	if (error)
+		goto exit_lock;
+
+	error = -EPERM;
+	if (!dir->i_op || !dir->i_op->mknod)
+		goto exit_lock;
+
+	DQUOT_INIT(dir);
+	error = dir->i_op->mknod(dir, dentry, mode, dev);
+exit_lock:
+	return error;
+}
+
 struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
 {
 	int error;
 	struct dentry *dir;
 	struct dentry *dentry, *retval;
 
-	mode &= ~current->fs->umask;
-	dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW);
+	dentry = lookup_dentry(filename, NULL, 0);
 	if (IS_ERR(dentry))
 		return dentry;
 
@@ -755,16 +777,8 @@
 	if (!check_parent(dir, dentry))
 		goto exit_lock;
 
-	error = may_create(dir->d_inode, dentry);
-	if (error)
-		goto exit_lock;
-
-	error = -EPERM;
-	if (!dir->d_inode->i_op || !dir->d_inode->i_op->mknod)
-		goto exit_lock;
+	error = vfs_mknod(dir->d_inode, dentry, mode, dev);
 
-	DQUOT_INIT(dir->d_inode);
-	error = dir->d_inode->i_op->mknod(dir->d_inode, dentry, mode, dev);
 exit_lock:
 	retval = ERR_PTR(error);
 	if (!error)
@@ -778,47 +792,66 @@
 {
 	int error;
 	char * tmp;
-	struct dentry * dentry;
+	struct dentry * dentry, *dir;
 
-	if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !capable(CAP_MKNOD)))
+	if (S_ISDIR(mode))
 		return -EPERM;
 	tmp = getname(filename);
 	if (IS_ERR(tmp))
 		return PTR_ERR(tmp);
 
-	error = -EINVAL;
 	lock_kernel();
+	dentry = lookup_dentry(tmp, NULL, 0);
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto out;
+	dir = lock_parent(dentry);
+	error = -ENOENT;
+	if (!check_parent(dir, dentry))
+		goto out_unlock;
 	switch (mode & S_IFMT) {
-	case 0:
-		mode |= S_IFREG;	/* fallthrough */
-	case S_IFREG:
-		mode &= ~current->fs->umask;
-		dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW);
-		if (IS_ERR(dentry))
-			error = PTR_ERR(dentry);
-		else {
-			struct dentry *dir = lock_parent(dentry);
-			error = -ENOENT;
-			if (check_parent(dir, dentry))
-				error = vfs_create(dir->d_inode, dentry, mode);
-			dput(dentry);
-		}
+	case 0: case S_IFREG:
+		error = vfs_create(dir->d_inode, dentry, mode);
 		break;
 	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
-		dentry = do_mknod(tmp,mode,dev);
-		error = PTR_ERR(dentry);
-		if (!IS_ERR(dentry)) {
-			dput(dentry);
-			error = 0;
-		}
+		error = vfs_mknod(dir->d_inode, dentry, mode, dev);
+		break;
+	case S_IFDIR:
+		error = -EPERM;
 		break;
+	default:
+		error = -EINVAL;
 	}
+out_unlock:
+	unlock_dir(dir);
+	dput(dentry);
+out:
 	unlock_kernel();
 	putname(tmp);
 
 	return error;
 }
 
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int error;
+
+	error = may_create(dir, dentry);
+	if (error)
+		goto exit_lock;
+
+	error = -EPERM;
+	if (!dir->i_op || !dir->i_op->mkdir)
+		goto exit_lock;
+
+	DQUOT_INIT(dir);
+	mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask;
+	error = dir->i_op->mkdir(dir, dentry, mode);
+
+exit_lock:
+	return error;
+}
+
 static inline int do_mkdir(const char * pathname, int mode)
 {
 	int error;
@@ -843,17 +876,7 @@
 	if (!check_parent(dir, dentry))
 		goto exit_lock;
 
-	error = may_create(dir->d_inode, dentry);
-	if (error)
-		goto exit_lock;
-
-	error = -EPERM;
-	if (!dir->d_inode->i_op || !dir->d_inode->i_op->mkdir)
-		goto exit_lock;
-
-	DQUOT_INIT(dir->d_inode);
-	mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask;
-	error = dir->d_inode->i_op->mkdir(dir->d_inode, dentry, mode);
+	error = vfs_mkdir(dir->d_inode, dentry, mode);
 
 exit_lock:
 	unlock_dir(dir);
@@ -1027,6 +1050,25 @@
 	return error;
 }
 
+int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+{
+	int error;
+
+	error = may_create(dir, dentry);
+	if (error)
+		goto exit_lock;
+
+	error = -EPERM;
+	if (!dir->i_op || !dir->i_op->symlink)
+		goto exit_lock;
+
+	DQUOT_INIT(dir);
+	error = dir->i_op->symlink(dir, dentry, oldname);
+
+exit_lock:
+	return error;
+}
+
 static inline int do_symlink(const char * oldname, const char * newname)
 {
 	int error;
@@ -1044,16 +1086,7 @@
 	if (!check_parent(dir, dentry))
 		goto exit_lock;
 
-	error = may_create(dir->d_inode, dentry);
-	if (error)
-		goto exit_lock;
-
-	error = -EPERM;
-	if (!dir->d_inode->i_op || !dir->d_inode->i_op->symlink)
-		goto exit_lock;
-
-	DQUOT_INIT(dir->d_inode);
-	error = dir->d_inode->i_op->symlink(dir->d_inode, dentry, oldname);
+	error = vfs_symlink(dir->d_inode, dentry, oldname);
 
 exit_lock:
 	unlock_dir(dir);
@@ -1083,10 +1116,43 @@
 	return error;
 }
 
+int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+{
+	struct inode *inode;
+	int error;
+
+	error = -ENOENT;
+	inode = old_dentry->d_inode;
+	if (!inode)
+		goto exit_lock;
+
+	error = may_create(dir, new_dentry);
+	if (error)
+		goto exit_lock;
+
+	error = -EXDEV;
+	if (dir->i_dev != inode->i_dev)
+		goto exit_lock;
+
+	/*
+	 * A link to an append-only or immutable file cannot be created.
+	 */
+	error = -EPERM;
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		goto exit_lock;
+	if (!dir->i_op || !dir->i_op->link)
+		goto exit_lock;
+
+	DQUOT_INIT(dir);
+	error = dir->i_op->link(old_dentry, dir, new_dentry);
+
+exit_lock:
+	return error;
+}
+
 static inline int do_link(const char * oldname, const char * newname)
 {
 	struct dentry *old_dentry, *new_dentry, *dir;
-	struct inode *inode;
 	int error;
 
 	/*
@@ -1113,32 +1179,7 @@
 	if (!check_parent(dir, new_dentry))
 		goto exit_lock;
 
-	error = -ENOENT;
-	inode = old_dentry->d_inode;
-	if (!inode)
-		goto exit_lock;
-
-	error = may_create(dir->d_inode, new_dentry);
-	if (error)
-		goto exit_lock;
-
-	error = -EXDEV;
-	if (dir->d_inode->i_dev != inode->i_dev)
-		goto exit_lock;
-
-	/*
-	 * A link to an append-only or immutable file cannot be created.
-	 */
-	error = -EPERM;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-		goto exit_lock;
-
-	error = -EPERM;
-	if (!dir->d_inode->i_op || !dir->d_inode->i_op->link)
-		goto exit_lock;
-
-	DQUOT_INIT(dir->d_inode);
-	error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry);
+	error = vfs_link(old_dentry, dir->d_inode, new_dentry);
 
 exit_lock:
 	unlock_dir(dir);
diff -u --recursive --new-file v2.3.49/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.49/linux/fs/ncpfs/dir.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/ncpfs/dir.c	Mon Mar  6 15:49:21 2000
@@ -75,10 +75,10 @@
 
 struct dentry_operations ncp_dentry_operations =
 {
-	ncp_lookup_validate,	/* d_revalidate(struct dentry *, int) */
-	ncp_hash_dentry,	/* d_hash */
-	ncp_compare_dentry,    	/* d_compare */
-	ncp_delete_dentry	/* d_delete(struct dentry *) */
+	d_revalidate:	ncp_lookup_validate,
+	d_hash:		ncp_hash_dentry,
+	d_compare:	ncp_compare_dentry,
+	d_delete:	ncp_delete_dentry,
 };
 
 
diff -u --recursive --new-file v2.3.49/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.3.49/linux/fs/nfs/dir.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/nfs/dir.c	Mon Mar  6 15:49:21 2000
@@ -654,12 +654,9 @@
 }
 
 struct dentry_operations nfs_dentry_operations = {
-	nfs_lookup_revalidate,	/* d_revalidate(struct dentry *, int) */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	nfs_dentry_delete,	/* d_delete(struct dentry *) */
-	nfs_dentry_release,	/* d_release(struct dentry *) */
-	NULL			/* d_iput */
+	d_revalidate:	nfs_lookup_revalidate,
+	d_delete:	nfs_dentry_delete,
+	d_release:	nfs_dentry_release,
 };
 
 #if 0 /* dead code */
diff -u --recursive --new-file v2.3.49/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.3.49/linux/fs/nfsd/nfsfh.c	Sat Feb 26 22:31:53 2000
+++ linux/fs/nfsd/nfsfh.c	Mon Mar  6 15:49:21 2000
@@ -63,7 +63,10 @@
 }
 
 /*
- * Read a directory and return the name of the specified entry.  i_sem is already down().
+ * Read a directory and return the name of the specified entry.
+ * i_sem is already down().
+ * The whole thing is a total BS. It should not be done via readdir(), damnit!
+ * Oh, well, as soon as it will be in filesystems...
  */
 static int get_ino_name(struct dentry *dentry, struct qstr *name, unsigned long ino)
 {
diff -u --recursive --new-file v2.3.49/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.49/linux/fs/nfsd/vfs.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/nfsd/vfs.c	Mon Mar  6 15:49:21 2000
@@ -801,7 +801,6 @@
 {
 	struct dentry	*dentry, *dchild;
 	struct inode	*dirp;
-	nfsd_dirop_t	opfunc = NULL;
 	int		err;
 
 	err = nfserr_perm;
@@ -856,45 +855,31 @@
 		goto out; 
 	}
 
+	if (!(iap->ia_valid & ATTR_MODE))
+		iap->ia_mode = 0;
+	iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
+
 	/*
 	 * Get the dir op function pointer.
 	 */
 	err = nfserr_perm;
 	switch (type) {
 	case S_IFREG:
-		opfunc = (nfsd_dirop_t) dirp->i_op->create;
+		err = vfs_create(dirp, dchild, iap->ia_mode);
 		break;
 	case S_IFDIR:
-		opfunc = (nfsd_dirop_t) dirp->i_op->mkdir;
+		err = vfs_mkdir(dirp, dchild, iap->ia_mode);
 		break;
 	case S_IFCHR:
 	case S_IFBLK:
-		/* The client is _NOT_ required to do security enforcement */
-		if(!capable(CAP_SYS_ADMIN))
-		{
-			err = -EPERM;
-			goto out;
-		}
 	case S_IFIFO:
 	case S_IFSOCK:
-		opfunc = dirp->i_op->mknod;
+		err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
 		break;
 	default:
 	        printk("nfsd: bad file type %o in nfsd_create\n", type);
-		err = nfserr_inval;
+		err = -EINVAL;
 	}
-	if (!opfunc)
-		goto out;
-
-	if (!(iap->ia_valid & ATTR_MODE))
-		iap->ia_mode = 0;
-	iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
-
-	/*
-	 * Call the dir op function to create the object.
-	 */
-	DQUOT_INIT(dirp);
-	err = opfunc(dirp, dchild, iap->ia_mode, rdev);
 	if (err < 0)
 		goto out_nfserr;
 
@@ -954,9 +939,6 @@
 	err = nfserr_notdir;
 	if(!dirp->i_op || !dirp->i_op->lookup)
 		goto out;
-	err = nfserr_perm;
-	if(!dirp->i_op->create)
-		goto out;
 
 	/*
 	 * Compose the response file handle.
@@ -1003,7 +985,7 @@
 		goto out;
 	}
 
-	err = dirp->i_op->create(dirp, dchild, iap->ia_mode);
+	err = vfs_create(dirp, dchild, iap->ia_mode);
 	if (err < 0)
 		goto out_nfserr;
 
@@ -1101,7 +1083,6 @@
 				struct iattr *iap)
 {
 	struct dentry	*dentry, *dnew;
-	struct inode	*dirp;
 	int		err;
 
 	err = nfserr_noent;
@@ -1113,11 +1094,6 @@
 		goto out;
 	dentry = fhp->fh_dentry;
 
-	err = nfserr_perm;
-	dirp = dentry->d_inode;
-	if (!dirp->i_op	|| !dirp->i_op->symlink)
-		goto out;
-
 	dnew = lookup_dentry(fname, dget(dentry), 0);
 	err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
@@ -1130,27 +1106,23 @@
 	if (err)
 		goto out_compose;
 
-	err = nfserr_exist;
-	if (!dnew->d_inode) {
-		DQUOT_INIT(dirp);
-		err = dirp->i_op->symlink(dirp, dnew, path);
-		if (!err) {
-			if (EX_ISSYNC(fhp->fh_export))
-				nfsd_sync_dir(dentry);
-			if (iap) {
-				iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/;
-				if (iap->ia_valid) {
-					iap->ia_valid |= ATTR_CTIME;
-					iap->ia_mode = (iap->ia_mode&S_IALLUGO)
-						| S_IFLNK;
-					err = notify_change(dnew, iap);
-					if (!err && EX_ISSYNC(fhp->fh_export))
-						write_inode_now(dentry->d_inode);
-			       }
-			}
-		} else
-			err = nfserrno(-err);
-	}
+	err = vfs_symlink(dentry->d_inode, dnew, path);
+	if (!err) {
+		if (EX_ISSYNC(fhp->fh_export))
+			nfsd_sync_dir(dentry);
+		if (iap) {
+			iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/;
+			if (iap->ia_valid) {
+				iap->ia_valid |= ATTR_CTIME;
+				iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+					| S_IFLNK;
+				err = notify_change(dnew, iap);
+				if (!err && EX_ISSYNC(fhp->fh_export))
+					write_inode_now(dentry->d_inode);
+		       }
+		}
+	} else
+		err = nfserrno(-err);
 	fh_unlock(fhp);
 
 	/* Compose the fh so the dentry will be freed ... */
@@ -1201,34 +1173,22 @@
 	if (err)
 		goto out_dput;
 
-	err = nfserr_exist;
-	if (dnew->d_inode)
-		goto out_unlock;
-
 	dold = tfhp->fh_dentry;
 	dest = dold->d_inode;
 
-	err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
-	if (dirp->i_dev != dest->i_dev)
-		goto out_unlock;
-
-	err = nfserr_perm;
-	if (IS_IMMUTABLE(dest) || IS_APPEND(dest))
-		goto out_unlock;
-	if (!dirp->i_op || !dirp->i_op->link)
-		goto out_unlock;
-
-	DQUOT_INIT(dirp);
-	err = dirp->i_op->link(dold, dirp, dnew);
+	err = vfs_link(dold, dirp, dnew);
 	if (!err) {
 		if (EX_ISSYNC(ffhp->fh_export)) {
 			nfsd_sync_dir(ddir);
 			write_inode_now(dest);
 		}
-	} else
-		err = nfserrno(-err);
+	} else {
+		if (err == -EXDEV && rqstp->rq_vers == 2)
+			err = nfserr_acces;
+		else
+			err = nfserrno(-err);
+	}
 
-out_unlock:
 	fh_unlock(ffhp);
 out_dput:
 	dput(dnew);
diff -u --recursive --new-file v2.3.49/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.3.49/linux/fs/ntfs/fs.c	Thu Mar  2 14:36:23 2000
+++ linux/fs/ntfs/fs.c	Mon Mar  6 15:49:21 2000
@@ -31,6 +31,7 @@
 
 /* Forward declarations */
 static struct inode_operations ntfs_dir_inode_operations;
+static struct file_operations ntfs_dir_operations;
 
 #define ITEM_SIZE 2040
 
diff -u --recursive --new-file v2.3.49/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.49/linux/fs/pipe.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/pipe.c	Sun Mar  5 11:05:02 2000
@@ -41,6 +41,7 @@
 	schedule();
 	remove_wait_queue(PIPE_WAIT(*inode), &wait);
 	current->state = TASK_RUNNING;
+	down(PIPE_SEM(*inode));
 }
 
 static ssize_t
@@ -81,9 +82,7 @@
 			PIPE_WAITING_READERS(*inode)--;
 			ret = -ERESTARTSYS;
 			if (signal_pending(current))
-				goto out_nolock;
-			if (down_interruptible(PIPE_SEM(*inode)))
-				goto out_nolock;
+				goto out;
 			ret = 0;
 			if (!PIPE_EMPTY(*inode))
 				break;
@@ -162,7 +161,6 @@
 	if (down_interruptible(PIPE_SEM(*inode)))
 		goto out_nolock;
 
-do_more_write:
 	/* No readers yields SIGPIPE.  */
 	if (!PIPE_READERS(*inode))
 		goto sigpipe;
@@ -182,9 +180,7 @@
 			PIPE_WAITING_WRITERS(*inode)--;
 			ret = -ERESTARTSYS;
 			if (signal_pending(current))
-				goto out_nolock;
-			if (down_interruptible(PIPE_SEM(*inode)))
-				goto out_nolock;
+				goto out;
 
 			if (!PIPE_READERS(*inode))
 				goto sigpipe;
@@ -230,20 +226,13 @@
 			pipe_wait(inode);
 			PIPE_WAITING_WRITERS(*inode)--;
 			if (signal_pending(current))
-				goto out_nolock;
-			if (down_interruptible(PIPE_SEM(*inode)))
-				goto out_nolock;
+				goto out;
 			if (!PIPE_READERS(*inode))
 				goto sigpipe;
 		} while (!PIPE_FREE(*inode));
 		ret = -EFAULT;
 	}
 
-	if (count && PIPE_WAITING_READERS(*inode) &&
-			!(filp->f_flags & O_NONBLOCK)) {
-		wake_up_interruptible_sync(PIPE_WAIT(*inode));
-		goto do_more_write;
-	}
 	/* Signal readers asynchronously that there is more data.  */
 	wake_up_interruptible(PIPE_WAIT(*inode));
 
diff -u --recursive --new-file v2.3.49/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.49/linux/fs/proc/base.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/proc/base.c	Mon Mar  6 15:49:21 2000
@@ -631,26 +631,19 @@
 
 static struct dentry_operations pid_fd_dentry_operations =
 {
-	pid_fd_revalidate,	/* revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	pid_delete_dentry	/* d_delete(struct dentry *) */
+	d_revalidate:	pid_fd_revalidate,
+	d_delete:	pid_delete_dentry,
 };
 
 static struct dentry_operations pid_dentry_operations =
 {
-	NULL,			/* revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	pid_delete_dentry	/* d_delete(struct dentry *) */
+	d_delete:	pid_delete_dentry,
 };
 
 static struct dentry_operations pid_base_dentry_operations =
 {
-	pid_base_revalidate,	/* revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	pid_delete_dentry	/* d_delete(struct dentry *) */
+	d_revalidate:	pid_base_revalidate,
+	d_delete:	pid_delete_dentry,
 };
 
 /* Lookups */
diff -u --recursive --new-file v2.3.49/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.3.49/linux/fs/proc/generic.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/proc/generic.c	Mon Mar  6 15:49:21 2000
@@ -226,10 +226,7 @@
 
 static struct dentry_operations proc_dentry_operations =
 {
-	NULL,			/* revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	proc_delete_dentry	/* d_delete(struct dentry *) */
+	d_delete:	proc_delete_dentry,
 };
 
 /*
diff -u --recursive --new-file v2.3.49/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.3.49/linux/fs/proc/proc_misc.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/proc/proc_misc.c	Thu Mar  2 22:46:07 2000
@@ -664,8 +664,11 @@
 		}
 	}
 #ifdef __powerpc__
-	entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
-	if (entry)
-		entry->proc_fops = &ppc_htab_operations;
+	{
+		extern struct file_operations ppc_htab_operations;
+		entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
+		if (entry)
+			entry->proc_fops = &ppc_htab_operations;
+	}
 #endif
 }
diff -u --recursive --new-file v2.3.49/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.49/linux/fs/proc/root.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/proc/root.c	Thu Mar  2 22:46:07 2000
@@ -70,9 +70,6 @@
 	proc_mkdir("openprom", 0);
 #endif
 	proc_tty_init();
-#ifdef __powerpc__
-	proc_register(&proc_root, &proc_root_ppc_htab);
-#endif
 #ifdef CONFIG_PROC_DEVICETREE
 	proc_device_tree_init();
 #endif
diff -u --recursive --new-file v2.3.49/linux/fs/readdir.c linux/fs/readdir.c
--- v2.3.49/linux/fs/readdir.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/readdir.c	Mon Mar  6 15:49:21 2000
@@ -13,6 +13,21 @@
 
 #include <asm/uaccess.h>
 
+int vfs_readdir(struct file *file,
+		int (*filler)(void *,const char *,int,off_t,ino_t),
+		void *buf)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int res = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+	down(&inode->i_sem);
+	res = file->f_op->readdir(file, buf, filler);
+	up(&inode->i_sem);
+out:
+	return res;
+}
+
 /*
  * Traditional linux readdir() handling..
  *
@@ -57,46 +72,24 @@
 {
 	int error;
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 	struct readdir_callback buf;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out_putf;
-
-	inode = dentry->d_inode;
-	if (!inode)
-		goto out_putf;
-
 	buf.count = 0;
 	buf.dirent = dirent;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, fillonedir);
-	up(&inode->i_sem);
-	if (error < 0)
-		goto out_putf;
-	error = buf.count;
+	lock_kernel();
+	error = vfs_readdir(file, fillonedir, &buf);
+	if (error >= 0)
+		error = buf.count;
+	unlock_kernel();
 
-out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -145,42 +138,22 @@
 asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count)
 {
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 	struct linux_dirent * lastdirent;
 	struct getdents_callback buf;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out_putf;
-
-	inode = dentry->d_inode;
-	if (!inode)
-		goto out_putf;
-
 	buf.current_dir = (struct linux_dirent *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, filldir);
-	up(&inode->i_sem);
+	lock_kernel();
+	error = vfs_readdir(file, filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 	error = buf.error;
@@ -191,8 +164,8 @@
 	}
 
 out_putf:
+	unlock_kernel();
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.3.49/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.3.49/linux/fs/smbfs/dir.c	Sat Feb 26 22:31:54 2000
+++ linux/fs/smbfs/dir.c	Mon Mar  6 15:49:21 2000
@@ -172,10 +172,10 @@
 
 static struct dentry_operations smbfs_dentry_operations =
 {
-	smb_lookup_validate,	/* d_revalidate(struct dentry *) */
-	smb_hash_dentry,	/* d_hash */
-	smb_compare_dentry,	/* d_compare */
-	smb_delete_dentry	/* d_delete(struct dentry *) */
+	d_revalidate:	smb_lookup_validate,
+	d_hash:		smb_hash_dentry,
+	d_compare:	smb_compare_dentry,
+	d_delete:	smb_delete_dentry,
 };
 
 /*
diff -u --recursive --new-file v2.3.49/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h
--- v2.3.49/linux/fs/udf/udfdecl.h	Thu Mar  2 14:36:23 2000
+++ linux/fs/udf/udfdecl.h	Thu Mar  2 22:44:40 2000
@@ -9,6 +9,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/types.h>
 
 #ifndef LINUX_VERSION_CODE
diff -u --recursive --new-file v2.3.49/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.3.49/linux/fs/umsdos/dir.c	Sat Feb 26 22:31:55 2000
+++ linux/fs/umsdos/dir.c	Mon Mar  6 15:49:21 2000
@@ -46,10 +46,8 @@
 
 struct dentry_operations umsdos_dentry_operations =
 {
-	umsdos_dentry_validate,	/* d_revalidate(struct dentry *, int) */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	umsdos_dentry_dput	/* d_delete(struct dentry *) */
+	d_revalidate:	umsdos_dentry_validate,
+	d_delete:	umsdos_dentry_dput,
 };
 
 struct UMSDOS_DIR_ONCE {
diff -u --recursive --new-file v2.3.49/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.3.49/linux/fs/vfat/namei.c	Sat Feb 26 22:31:55 2000
+++ linux/fs/vfat/namei.c	Mon Mar  6 15:49:21 2000
@@ -59,28 +59,22 @@
 
 static struct dentry_operations vfat_dentry_ops[4] = {
 	{
-		NULL,			/* d_revalidate */
-		vfat_hashi,
-		vfat_cmpi,
-		NULL			/* d_delete */
+		d_hash:		vfat_hashi,
+		d_compare:	vfat_cmpi,
 	},
 	{
-		vfat_revalidate,
-		vfat_hashi,
-		vfat_cmpi,
-		NULL			/* d_delete */
+		d_revalidate:	vfat_revalidate,
+		d_hash:		vfat_hashi,
+		d_compare:	vfat_cmpi,
 	},
 	{
-		NULL, 			/* d_revalidate */
-		vfat_hash,
-		vfat_cmp,
-		NULL			/* d_delete */
+		d_hash:		vfat_hash,
+		d_compare:	vfat_cmp,
 	},
 	{
-		vfat_revalidate,
-		vfat_hash,
-		vfat_cmp,
-		NULL			/* d_delete */
+		d_revalidate:	vfat_revalidate,
+		d_hash:		vfat_hash,
+		d_compare:	vfat_cmp,
 	}
 };
 
diff -u --recursive --new-file v2.3.49/linux/include/asm-i386/hw_irq.h linux/include/asm-i386/hw_irq.h
--- v2.3.49/linux/include/asm-i386/hw_irq.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-i386/hw_irq.h	Tue Mar  7 11:25:12 2000
@@ -179,6 +179,10 @@
 	"jmp common_interrupt");
 
 extern unsigned long prof_cpu_mask;
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
 /*
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
diff -u --recursive --new-file v2.3.49/linux/include/asm-ppc/types.h linux/include/asm-ppc/types.h
--- v2.3.49/linux/include/asm-ppc/types.h	Sat Feb 26 22:31:59 2000
+++ linux/include/asm-ppc/types.h	Thu Mar  2 22:46:07 2000
@@ -2,10 +2,7 @@
 #define _PPC_TYPES_H
 
 #ifndef __ASSEMBLY__
-/*
- * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
- * header files exported to user space
- */
+#ifdef __KERNEL__
 
 typedef unsigned short umode_t;
 
@@ -41,8 +38,6 @@
 typedef struct {
 	u32 u[4];
 } __attribute((aligned(16))) vector128;
-
-#ifdef __KERNEL__
 
 #define BITS_PER_LONG 32
 
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/cache.h linux/include/asm-sh/cache.h
--- v2.3.49/linux/include/asm-sh/cache.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/cache.h	Sun Mar  5 09:33:55 2000
@@ -1,5 +1,7 @@
-/*
+/* $Id: cache.h,v 1.3 1999/12/11 12:31:51 gniibe Exp $
+ *
  * include/asm-sh/cache.h
+ *
  * Copyright 1999 (C) Niibe Yutaka
  */
 #ifndef __ASM_SH_CACHE_H
@@ -10,18 +12,6 @@
 #define        L1_CACHE_BYTES  16
 #elif defined(__SH4__)
 #define        L1_CACHE_BYTES  32
-#endif
-
-#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-
-#define        SMP_CACHE_BYTES L1_CACHE_BYTES
-
-#ifdef MODULE
-#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
-#else
-#define __cacheline_aligned					\
-  __attribute__((__aligned__(L1_CACHE_BYTES),			\
-		 __section__(".data.cacheline_aligned")))
 #endif
 
 extern void cache_flush_area(unsigned long start, unsigned long end);
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/div64.h linux/include/asm-sh/div64.h
--- v2.3.49/linux/include/asm-sh/div64.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/div64.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,10 @@
+#ifndef __ASM_SH_DIV64
+#define __ASM_SH_DIV64
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+#endif /* __ASM_SH_DIV64 */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/dma.h linux/include/asm-sh/dma.h
--- v2.3.49/linux/include/asm-sh/dma.h	Wed Oct 27 16:34:12 1999
+++ linux/include/asm-sh/dma.h	Sun Mar  5 09:33:55 2000
@@ -1,14 +1,16 @@
 #ifndef __ASM_SH_DMA_H
 #define __ASM_SH_DMA_H
 
-/* Don't define MAX_DMA_ADDRESS; it's useless on the SuperH and any
-   occurrence should be flagged as an error.  */
+#include <asm/io.h>		/* need byte IO */
 
 #define MAX_DMA_CHANNELS 8
 
 /* The maximum address that we can perform a DMA transfer to on this platform */
+/* Don't define MAX_DMA_ADDRESS; it's useless on the SuperH and any
+   occurrence should be flagged as an error.  */
+/* But... */
 /* XXX: This is not applicable to SuperH, just needed for alloc_bootmem */
-#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x1000000)
+#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x10000000)
 
 extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
 extern void free_dma(unsigned int dmanr);	/* release it again */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/elf.h linux/include/asm-sh/elf.h
--- v2.3.49/linux/include/asm-sh/elf.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/elf.h	Sun Mar  5 09:33:55 2000
@@ -14,10 +14,7 @@
 #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
-/* Though SH-3 has no floating point regs.. */
-#define ELF_NFPREG 34
-typedef double elf_fpreg_t;
-typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+typedef struct user_fpu_struct elf_fpregset_t;
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/hardirq.h linux/include/asm-sh/hardirq.h
--- v2.3.49/linux/include/asm-sh/hardirq.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/hardirq.h	Sun Mar  5 09:33:55 2000
@@ -6,13 +6,15 @@
 extern unsigned int local_irq_count[NR_CPUS];
 #define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
 
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+
 #ifndef __SMP__
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
 
-#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+#define irq_enter(cpu, irq)	(local_irq_count[cpu]++)
+#define irq_exit(cpu, irq)	(local_irq_count[cpu]--)
 
 #define synchronize_irq()	barrier()
 
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/hdreg.h linux/include/asm-sh/hdreg.h
--- v2.3.49/linux/include/asm-sh/hdreg.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/hdreg.h	Sun Mar  5 09:33:55 2000
@@ -7,6 +7,6 @@
 #ifndef __ASM_SH_HDREG_H
 #define __ASM_SH_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+typedef unsigned int ide_ioreg_t;
 
 #endif /* __ASM_SH_HDREG_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/highmem.h linux/include/asm-sh/highmem.h
--- v2.3.49/linux/include/asm-sh/highmem.h	Wed Oct 27 16:34:12 1999
+++ linux/include/asm-sh/highmem.h	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-/*
- * highmem.h: virtual kernel memory mappings for high memory
- *
- * Used in CONFIG_HIGHMEM systems for memory pages which
- * are not addressable by direct kernel virtual adresses.
- *
- * Copyright (C) 1999 Gerhard Wichert, Siemens AG
- *		      Gerhard.Wichert@pdb.siemens.de
- *
- *
- * Redesigned the x86 32-bit VM architecture to deal with 
- * up to 16 Terrabyte physical memory. With current x86 CPUs
- * we now support up to 64 Gigabytes physical RAM.
- *
- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
- */
-
-#ifndef _ASM_HIGHMEM_H
-#define _ASM_HIGHMEM_H
-
-#include <linux/init.h>
-
-/* undef for production */
-#define HIGHMEM_DEBUG 1
-
-/* declarations for highmem.c */
-extern unsigned long highstart_pfn, highend_pfn;
-
-extern pte_t *kmap_pte;
-extern pgprot_t kmap_prot;
-
-extern void kmap_init(void) __init;
-
-/* kmap helper functions necessary to access the highmem pages in kernel */
-#include <asm/pgtable.h>
-#include <asm/kmap_types.h>
-
-extern inline unsigned long kmap(struct page *page, enum km_type type)
-{
-	if (page < highmem_start_page)
-		return page_address(page);
-	{
-		enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id();
-		unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN+idx);
-
-#if HIGHMEM_DEBUG
-		if (!pte_none(*(kmap_pte-idx)))
-		{
-			__label__ here;
-		here:
-			printk(KERN_ERR "not null pte on CPU %d from %p\n",
-			       smp_processor_id(), &&here);
-		}
-#endif
-		set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
-		__flush_tlb_one(vaddr);
-
-		return vaddr;
-	}
-}
-
-extern inline void kunmap(unsigned long vaddr, enum km_type type)
-{
-#if HIGHMEM_DEBUG
-	enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id();
-	if ((vaddr & PAGE_MASK) == __fix_to_virt(FIX_KMAP_BEGIN+idx))
-	{
-		/* force other mappings to Oops if they'll try to access
-		   this pte without first remap it */
-		pte_clear(kmap_pte-idx);
-		__flush_tlb_one(vaddr);
-	}
-#endif
-}
-
-extern inline void kmap_check(void)
-{
-#if HIGHMEM_DEBUG
-	int idx_base = KM_TYPE_NR*smp_processor_id(), i;
-	for (i = idx_base; i < idx_base+KM_TYPE_NR; i++)
-		if (!pte_none(*(kmap_pte-i)))
-			BUG();
-#endif
-}
-#endif /* _ASM_HIGHMEM_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h
--- v2.3.49/linux/include/asm-sh/ide.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/ide.h	Sun Mar  5 09:33:55 2000
@@ -17,7 +17,7 @@
 #include <linux/config.h>
 
 #ifndef MAX_HWIFS
-#define MAX_HWIFS	10
+#define MAX_HWIFS	1	/* XXX: For my board -- gniibe */
 #endif
 
 #define ide__sti()	__sti()
@@ -25,12 +25,8 @@
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
-		case 0x1f0: return 14;
-		case 0x170: return 15;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		case 0x1e0: return 8;
-		case 0x160: return 12;
+		case 0xba0001f0: return 14;
+		case 0xba000170: return 14;
 		default:
 			return 0;
 	}
@@ -39,12 +35,10 @@
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	switch (index) {
-		case 0:	return 0x1f0;
-		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		case 4: return 0x1e0;
-		case 5: return 0x160;
+		case 0:	
+			return 0xba0001f0;
+		case 1:	
+			return 0xba000170;
 		default:
 			return 0;
 	}
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/io.h linux/include/asm-sh/io.h
--- v2.3.49/linux/include/asm-sh/io.h	Tue Dec  7 09:32:51 1999
+++ linux/include/asm-sh/io.h	Sun Mar  5 09:33:55 2000
@@ -14,32 +14,38 @@
 
 #include <asm/cache.h>
 
+#define inb_p	inb
+#define outb_p	outb
+
+#define inw_p	inw
+#define outw_p	outw
+
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
 extern __inline__ unsigned long readb(unsigned long addr)
 {
-       return *(volatile unsigned char*)addr;
+	return *(volatile unsigned char*)addr;
 }
 
 extern __inline__ unsigned long readw(unsigned long addr)
 {
-       return *(volatile unsigned short*)addr;
+	return *(volatile unsigned short*)addr;
 }
 
 extern __inline__ unsigned long readl(unsigned long addr)
 {
-       return *(volatile unsigned long*)addr;
+	return *(volatile unsigned long*)addr;
 }
 
 extern __inline__ void writeb(unsigned char b, unsigned long addr)
 {
-       *(volatile unsigned char*)addr = b;
+	*(volatile unsigned char*)addr = b;
 }
 
 extern __inline__ void writew(unsigned short b, unsigned long addr)
 {
-       *(volatile unsigned short*)addr = b;
+	*(volatile unsigned short*)addr = b;
 }
 
 extern __inline__ void writel(unsigned int b, unsigned long addr)
@@ -49,27 +55,27 @@
 
 extern __inline__ unsigned long inb_local(unsigned long addr)
 {
-       return readb(addr);
+	return readb(addr);
 }
 
 extern __inline__ void outb_local(unsigned char b, unsigned long addr)
 {
-       return writeb(b,addr);
+	return writeb(b,addr);
 }
 
 extern __inline__ unsigned long inb(unsigned long addr)
 {
-       return readb(addr);
+	return readb(addr);
 }
 
 extern __inline__ unsigned long inw(unsigned long addr)
 {
-       return readw(addr);
+	return readw(addr);
 }
 
 extern __inline__ unsigned long inl(unsigned long addr)
 {
-       return readl(addr);
+	return readl(addr);
 }
 
 extern __inline__ void insb(unsigned long addr, void *buffer, int count)
@@ -123,6 +129,9 @@
 	while(count--) outl(*buf++, addr);
 }
 
+#define ctrl_in(addr)		*(addr)
+#define ctrl_out(data,addr)	*(addr) = (data)
+
 extern __inline__ unsigned long ctrl_inb(unsigned long addr)
 {
        return *(volatile unsigned char*)addr;
@@ -145,7 +154,7 @@
 
 extern __inline__ void ctrl_outw(unsigned short b, unsigned long addr)
 {
-       *(volatile unsigned short*)addr = b;
+	*(volatile unsigned short*)addr = b;
 }
 
 extern __inline__ void ctrl_outl(unsigned int b, unsigned long addr)
@@ -153,12 +162,9 @@
         *(volatile unsigned long*)addr = b;
 }
 
-#define inb_p inb
-#define outb_p outb
-
 #ifdef __KERNEL__
 
-#define IO_SPACE_LIMIT 0xffff
+#define IO_SPACE_LIMIT 0xffffffff
 
 #include <asm/addrspace.h>
 
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/ipcbuf.h linux/include/asm-sh/ipcbuf.h
--- v2.3.49/linux/include/asm-sh/ipcbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/ipcbuf.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,29 @@
+#ifndef __ASM_SH_IPCBUF_H__
+#define __ASM_SH_IPCBUF_H__
+
+/*
+ * The ipc64_perm structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
+	__kernel_mode_t		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+#endif /* __ASM_SH_IPCBUF_H__ */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/irq.h linux/include/asm-sh/irq.h
--- v2.3.49/linux/include/asm-sh/irq.h	Sun Nov  7 16:37:34 1999
+++ linux/include/asm-sh/irq.h	Sun Mar  5 09:33:55 2000
@@ -12,8 +12,8 @@
 #include <linux/config.h>
 
 #define TIMER_IRQ		16	/* Hard-wired */
-#define TIMER_IRP_OFFSET	12
-#define TIMER_PRIORITY		 1
+#define TIMER_IPR_OFFSET	12
+#define TIMER_PRIORITY		 2
 
 #if defined(__SH4__)
 /*
@@ -39,5 +39,6 @@
  */
 extern void set_ipr_data(unsigned int irq, int offset, int priority);
 extern void make_onChip_irq(unsigned int irq);
+extern void make_imask_irq(unsigned int irq);
 
 #endif /* __ASM_SH_IRQ_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/mmu_context.h linux/include/asm-sh/mmu_context.h
--- v2.3.49/linux/include/asm-sh/mmu_context.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sh/mmu_context.h	Sun Mar  5 09:33:55 2000
@@ -11,9 +11,6 @@
      (b) ASID (Address Space IDentifier)
  */
 
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
-{
-}
 /*
  * Cache of MMU context last used.
  */
@@ -27,6 +24,11 @@
 /* ASID is 8-bit value, so it can't be 0x100 */
 #define MMU_NO_ASID			0x100
 
+/*
+ * Virtual Page Number mask
+ */
+#define MMU_VPN_MASK	0xfffff000
+
 extern __inline__ void
 get_new_mmu_context(struct mm_struct *mm)
 {
@@ -114,16 +116,22 @@
 
 extern __inline__ void set_asid(unsigned long asid)
 {
-	__asm__ __volatile__ ("mov.l	%0,%1"
-			      : /* no output */
-			      : "r" (asid), "m" (__m(MMU_PTEH)));
+	unsigned long __dummy;
+
+	__asm__ __volatile__ ("mov.l	%2, %0\n\t"
+			      "and	%3, %0\n\t"
+			      "or	%1, %0\n\t"
+			      "mov.l	%0, %2"
+			      : "=&r" (__dummy)
+			      : "r" (asid), "m" (__m(MMU_PTEH)),
+			        "r" (0xffffff00));
 }
 
 extern __inline__ unsigned long get_asid(void)
 {
 	unsigned long asid;
 
-	__asm__ __volatile__ ("mov.l	%1,%0"
+	__asm__ __volatile__ ("mov.l	%1, %0"
 			      : "=r" (asid)
 			      : "m" (__m(MMU_PTEH)));
 	asid &= MMU_CONTEXT_ASID_MASK;
@@ -146,19 +154,23 @@
 				 struct mm_struct *next,
 				 struct task_struct *tsk, unsigned int cpu)
 {
+	set_bit(cpu, &next->cpu_vm_mask);
 	if (prev != next) {
 		unsigned long __pgdir = (unsigned long)next->pgd;
 
-		__asm__ __volatile__("mov.l	%0,%1"
+		__asm__ __volatile__("mov.l	%0, %1"
 				     : /* no output */
 				     : "r" (__pgdir), "m" (__m(MMU_TTB)));
 		activate_context(next);
 		clear_bit(cpu, &prev->cpu_vm_mask);
 	}
-	set_bit(cpu, &next->cpu_vm_mask);
 }
 
 #define activate_mm(prev, next) \
 	switch_mm((prev),(next),NULL,smp_processor_id())
 
+extern __inline__ void
+enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
 #endif /* __ASM_SH_MMU_CONTEXT_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/msgbuf.h linux/include/asm-sh/msgbuf.h
--- v2.3.49/linux/include/asm-sh/msgbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/msgbuf.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,31 @@
+#ifndef __ASM_SH_MSGBUF_H
+#define __ASM_SH_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	unsigned long	__unused1;
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	unsigned long	__unused2;
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long	__unused3;
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif /* __ASM_SH_MSGBUF_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/page.h linux/include/asm-sh/page.h
--- v2.3.49/linux/include/asm-sh/page.h	Wed Feb 16 17:03:52 2000
+++ linux/include/asm-sh/page.h	Sun Mar  5 09:33:55 2000
@@ -19,6 +19,7 @@
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
+#define PTE_MASK	PAGE_MASK
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
@@ -39,6 +40,9 @@
 #define pgd_val(x)	((x).pgd)
 #define pgprot_val(x)	((x).pgprot)
 
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
 
 #endif /* !__ASSEMBLY__ */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- v2.3.49/linux/include/asm-sh/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/pci.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,143 @@
+#ifndef __ASM_SH_PCI_H
+#define __ASM_SH_PCI_H
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+   already-configured bus numbers - to be used for buggy BIOSes
+   or architectures with incomplete PCI setup by the loader */
+
+#define pcibios_assign_all_busses()	0
+
+#ifdef __KERNEL__
+
+/* Dynamic DMA mapping stuff.
+ * SuperH has everything mapped statically like x86.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include <linux/string.h>
+#include <asm/io.h>
+
+struct pci_dev;
+
+/* Allocate and map kernel buffer using consistent mode DMA for a device.
+ * hwdev should be valid struct pci_dev pointer for PCI devices,
+ * NULL for PCI-like buses (ISA, EISA).
+ * Returns non-NULL cpu-view pointer to the buffer if successful and
+ * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
+ * is undefined.
+ */
+extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				  dma_addr_t *dma_handle);
+
+/* Free and unmap a consistent DMA buffer.
+ * cpu_addr is what was returned from pci_alloc_consistent,
+ * size must be the same as what as passed into pci_alloc_consistent,
+ * and likewise dma_addr must be the same as what *dma_addrp was set to.
+ *
+ * References to the memory and mappings associated with cpu_addr/dma_addr
+ * past this call are illegal.
+ */
+extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+				void *vaddr, dma_addr_t dma_handle);
+
+/* Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size)
+{
+	return virt_to_bus(ptr);
+}
+
+/* Unmap a single streaming mode DMA translation.  The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+				    size_t size)
+{
+	/* Nothing to do */
+}
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			     int nents)
+{
+	return nents;
+}
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+				int nents)
+{
+	/* Nothing to do */
+}
+
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+				       dma_addr_t dma_handle,
+				       size_t size)
+{
+	/* Nothing to do */
+}
+
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+				   struct scatterlist *sg,
+				   int nelems)
+{
+	/* Nothing to do */
+}
+
+/* These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg)	(virt_to_bus((sg)->address))
+#define sg_dma_len(sg)		((sg)->length)
+
+#endif /* __KERNEL__ */
+
+
+#endif /* __ASM_SH_PCI_H */
+
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/pgalloc-2level.h linux/include/asm-sh/pgalloc-2level.h
--- v2.3.49/linux/include/asm-sh/pgalloc-2level.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/pgalloc-2level.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,23 @@
+#ifndef __ASM_SH_PGALLOC_2LEVEL_H
+#define __ASM_SH_PGALLOC_2LEVEL_H
+
+/*
+ * traditional two-level paging, page table allocation routines:
+ */
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd) { }
+extern __inline__ void free_pmd_slow(pmd_t *pmd) { }
+
+extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+	if (!pgd)
+		BUG();
+	return (pmd_t *) pgd;
+}
+
+#endif /* __ASM_SH_PGALLOC_2LEVEL_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/pgalloc.h linux/include/asm-sh/pgalloc.h
--- v2.3.49/linux/include/asm-sh/pgalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/pgalloc.h	Tue Mar  7 11:10:03 2000
@@ -0,0 +1,182 @@
+#ifndef __ASM_SH_PGALLOC_H
+#define __ASM_SH_PGALLOC_H
+
+#include <asm/processor.h>
+#include <linux/threads.h>
+
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+
+#include <asm/pgalloc-2level.h>
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
+
+extern __inline__ pgd_t *get_pgd_slow(void)
+{
+	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+	if (ret) {
+		memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+		memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	}
+	return ret;
+}
+
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	if ((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
+}
+
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+	free_page((unsigned long)pgd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+	free_page((unsigned long)pte);
+}
+
+#define pte_free_kernel(pte)    free_pte_slow(pte)
+#define pte_free(pte)	   free_pte_slow(pte)
+#define pgd_free(pgd)	   free_pgd_slow(pgd)
+#define pgd_alloc()	     get_pgd_fast()
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	if (!pmd)
+		BUG();
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_pte_fast();
+		
+		if (!page)
+			return get_pte_kernel_slow(pmd, address);
+		set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page)));
+		return page + address;
+	}
+	if (pmd_bad(*pmd)) {
+		__handle_bad_pmd_kernel(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+
+	if (pmd_none(*pmd))
+		goto getnew;
+	if (pmd_bad(*pmd))
+		goto fix;
+	return (pte_t *)pmd_page(*pmd) + address;
+getnew:
+{
+	unsigned long page = (unsigned long) get_pte_fast();
+	
+	if (!page)
+		return get_pte_slow(pmd, address);
+	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page)));
+	return (pte_t *)page + address;
+}
+fix:
+	__handle_bad_pmd(pmd);
+	return NULL;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free(pmd_t * pmd)
+{
+}
+
+#define pmd_free_kernel		pmd_free
+#define pmd_alloc_kernel	pmd_alloc
+
+extern int do_check_pgt_cache(int, int);
+
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+	struct task_struct * p;
+	pgd_t *pgd;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
+}
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *
+ */
+
+extern void flush_tlb(void);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+			    unsigned long end);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
+
+#endif /* __ASM_SH_PGALLOC_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/pgtable-2level.h linux/include/asm-sh/pgtable-2level.h
--- v2.3.49/linux/include/asm-sh/pgtable-2level.h	Sun Nov  7 16:37:34 1999
+++ linux/include/asm-sh/pgtable-2level.h	Sun Mar  5 09:33:55 2000
@@ -34,27 +34,25 @@
 extern inline int pgd_present(pgd_t pgd)	{ return 1; }
 #define pgd_clear(xp)	do { } while (0)
 
+/*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+/*
+ * (pmds are folded into pgds so this doesnt get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
 #define pgd_page(pgd) \
 ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
 
 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
 	return (pmd_t *) dir;
-}
-
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd) { }
-extern __inline__ void free_pmd_slow(pmd_t *pmd) { }
-
-extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	if (!pgd)
-		BUG();
-	return (pmd_t *) pgd;
 }
 
 #endif /* __ASM_SH_PGTABLE_2LEVEL_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- v2.3.49/linux/include/asm-sh/pgtable.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-sh/pgtable.h	Sun Mar  5 09:33:55 2000
@@ -13,6 +13,7 @@
 #include <linux/threads.h>
 
 extern pgd_t swapper_pg_dir[1024];
+extern void paging_init(void);
 
 #if defined(__sh3__)
 /* Cache flushing:
@@ -32,6 +33,7 @@
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_page(vma,pg)		do { } while (0)
 #elif defined(__SH4__)
 /*
  *  Caches are broken on SH-4, so we need them.
@@ -41,48 +43,28 @@
 extern void flush_cache_range(struct mm_struct *mm, unsigned long start,
 			      unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
-extern void flush_page_to_ram(unsigned long page);
+extern void __flush_page_to_ram(unsigned long page_va);
+#define flush_page_to_ram(page)	__flush_page_to_ram(page_address(page))
 extern void flush_icache_range(unsigned long start, unsigned long end);
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg);
 #endif
 
-/* TLB flushing:
- *
- *  - flush_tlb_all() flushes all processes TLB entries
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
- *  - flush_tlb_page(mm, vmaddr) flushes a single page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
- */
-extern void flush_tlb_all(void);
-extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
-			    unsigned long end);
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-				      unsigned long start, unsigned long end)
-{
-}
-
 /*
  * Basically we have the same two-level (which is the logical three level
  * Linux page table layout folded) page tables as the i386.
  */
 
-#endif /* !__ASSEMBLY__ */
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page))
 
-#define pgd_quicklist (current_cpu_data.pgd_quick)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (current_cpu_data.pte_quick)
-#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+#endif /* !__ASSEMBLY__ */
 
 #include <asm/pgtable-2level.h>
 
-/*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
 #define __beep() asm("")
 
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -105,10 +87,10 @@
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END	P4SEG
 
-#define _PAGE_READ 	0x001  /* software: read access alowed */
+#define _PAGE_READ 	0x001  /* software: read access allowed */
 #define _PAGE_ACCESSED	0x002  /* software: page referenced */
 #define _PAGE_DIRTY	0x004  /* D-bit   : page changed */
-/*		 	0x008  */
+#define _PAGE_CACHABLE	0x008  /* C-bit   : cachable */
 /*		 	0x010  */
 #define _PAGE_RW	0x020  /* PR0-bit : write access allowed */
 #define _PAGE_USER	0x040  /* PR1-bit : user space access allowed */
@@ -117,26 +99,26 @@
 
 #if defined(__sh3__)
 /* Mask which drop software flags */
-#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff164
-/* Flags defalult: SZ=1 (4k-byte), C=1 (cachable), SH=0 (not shared) */
-#define _PAGE_FLAGS_HARDWARE_DEFAULT	0x00000018
+#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff16c
+/* Flags defalult: SZ=1 (4k-byte), C=0 (non-cachable), SH=0 (not shared) */
+#define _PAGE_FLAGS_HARDWARE_DEFAULT	0x00000010
 #elif defined(__SH4__)
 /* Mask which drops software flags */
-#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff164
-/* Flags defalult: SZ=01 (4k-byte), C=1 (cachable), SH=0 (not shared), WT=0 */
-#define _PAGE_FLAGS_HARDWARE_DEFAULT	0x00000018
+#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff16c
+/* Flags defalult: SZ=01 (4k-byte), C=0 (non-cachable), SH=0 (not shared), WT=0 */
+#define _PAGE_FLAGS_HARDWARE_DEFAULT	0x00000010
 #endif
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY)
 
-#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED)
 
 /*
  * As i386 and MIPS, SuperH can't do page protection for execute, and
@@ -163,23 +145,6 @@
 #define __S111	PAGE_SHARED
 
 /*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
-
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern unsigned long empty_zero_page[1024];
-#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page))
-
-/*
  * Handling allocation failures during page table setup.
  */
 extern void __handle_bad_pmd(pmd_t * pmd);
@@ -187,19 +152,19 @@
 
 #define pte_none(x)	(!pte_val(x))
 #define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
-#define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
+#define pte_clear(xp)	do { set_pte(xp, __pte(0)); } while (0)
 #define pte_pagenr(x)	((unsigned long)(((pte_val(x) -__MEMORY_START) >> PAGE_SHIFT)))
 
 #define pmd_none(x)	(!pmd_val(x))
-#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
-#define pmd_clear(xp)	do { pmd_val(*(xp)) = 0; } while (0)
+#define pmd_clear(xp)	do { set_pmd(xp, __pmd(0)); } while (0)
+#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
 
 /*
  * Permanent address of a page. Obviously must never be
  * called on a highmem page.
  */
-#define page_address(page) ({ PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT) + __MEMORY_START; })
+#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
 #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
 #define pte_page(x) (mem_map+pte_pagenr(x))
 
@@ -212,39 +177,40 @@
 extern inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; }
 extern inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_RW; }
-       
-extern inline pte_t pte_rdprotect(pte_t pte){ pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte){ pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte){ pte_val(pte) &= ~_PAGE_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _PAGE_RW; return pte; }
+
+extern inline pte_t pte_rdprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
+ *
+ * extern pte_t mk_pte(struct page *page, pgprot_t pgprot)
  */
-extern inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
-{
-	pte_t __pte;
-
-	pte_val(__pte) = (page-mem_map)*(unsigned long long)PAGE_SIZE +
-				__MEMORY_START + pgprot_val(pgprot);
-	return __pte;
-}
+#define mk_pte(page,pgprot)						\
+({	pte_t __pte;							\
+									\
+	set_pte(&__pte, __pte(((page)-mem_map) * 			\
+		(unsigned long long)PAGE_SIZE + pgprot_val(pgprot) +	\
+		__MEMORY_START));					\
+	__pte;								\
+})
 
 /* This takes a physical page address that is used by the remapping functions */
 #define mk_pte_phys(physpage, pgprot) \
-({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
+({ pte_t __pte; set_pte(&__pte, __pte(physpage + pgprot_val(pgprot))); __pte; })
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+{ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; }
 
-#define page_pte_prot(page,prot) mk_pte(page, prot)
 #define page_pte(page) page_pte_prot(page, __pgprot(0))
 
 #define pmd_page(pmd) \
@@ -266,157 +232,6 @@
 		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \
 			__pte_offset(address))
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
-extern __inline__ pgd_t *get_pgd_slow(void)
-{
-	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
-
-	if (ret) {
-		/* Clear User space */
-		memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-
-		/* XXX: Copy vmalloc-ed space??? */
-		memcpy(ret + USER_PTRS_PER_PGD,
-		       swapper_pg_dir + USER_PTRS_PER_PGD,
-		       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-	}
-	return ret;
-}
-
-extern __inline__ pgd_t *get_pgd_fast(void)
-{
-	unsigned long *ret;
-
-	if ((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		pgtable_cache_size--;
-	} else
-		ret = (unsigned long *)get_pgd_slow();
-	return (pgd_t *)ret;
-}
-
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
-}
-
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
-{
-	free_page((unsigned long)pgd);
-}
-
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
-extern __inline__ pte_t *get_pte_fast(void)
-{
-	unsigned long *ret;
-
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size--;
-	}
-	return (pte_t *)ret;
-}
-
-extern __inline__ void free_pte_fast(pte_t *pte)
-{
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	pgtable_cache_size++;
-}
-
-extern __inline__ void free_pte_slow(pte_t *pte)
-{
-	free_page((unsigned long)pte);
-}
-
-#define pte_free_kernel(pte)    free_pte_slow(pte)
-#define pte_free(pte)           free_pte_slow(pte)
-#define pgd_free(pgd)           free_pgd_slow(pgd)
-#define pgd_alloc()             get_pgd_fast()
-
-extern __inline__ pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_pte_fast();
-		
-		if (!page)
-			return get_pte_kernel_slow(pmd, address);
-		pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-extern __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
-	if (pmd_none(*pmd))
-		goto getnew;
-	if (pmd_bad(*pmd))
-		goto fix;
-	return (pte_t *)pmd_page(*pmd) + address;
-getnew:
-{
-	unsigned long page = (unsigned long) get_pte_fast();
-	
-	if (!page)
-		return get_pte_slow(pmd, address);
-	pmd_val(*pmd) = _PAGE_TABLE + __pa(page);
-	return (pte_t *)page + address;
-}
-fix:
-	__handle_bad_pmd(pmd);
-	return NULL;
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern inline void pmd_free(pmd_t * pmd)
-{
-}
-
-#define pmd_free_kernel		pmd_free
-#define pmd_alloc_kernel	pmd_alloc
-
-extern int do_check_pgt_cache(int, int);
-
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
-	struct task_struct * p;
-	pgd_t *pgd;
-        
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
-		pgd[address >> PGDIR_SHIFT] = entry;
-}
-
-extern pgd_t swapper_pg_dir[1024];
 
 extern void update_mmu_cache(struct vm_area_struct * vma,
 			     unsigned long address, pte_t pte);
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/posix_types.h linux/include/asm-sh/posix_types.h
--- v2.3.49/linux/include/asm-sh/posix_types.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/posix_types.h	Sun Mar  5 09:33:55 2000
@@ -24,6 +24,13 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
+typedef unsigned int	__kernel_uid32_t;
+typedef unsigned int	__kernel_gid32_t;
+
+typedef unsigned short	__kernel_old_uid_t;
+typedef unsigned short	__kernel_old_gid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
@@ -38,6 +45,7 @@
 } __kernel_fsid_t;
 
 #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
 #undef	__FD_SET
 static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
 {
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/processor.h linux/include/asm-sh/processor.h
--- v2.3.49/linux/include/asm-sh/processor.h	Thu Nov 11 20:11:52 1999
+++ linux/include/asm-sh/processor.h	Sun Mar  5 09:33:55 2000
@@ -1,7 +1,7 @@
 /*
  * include/asm-sh/processor.h
  *
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999, 2000  Niibe Yutaka
  */
 
 #ifndef __ASM_SH_PROCESSOR_H
@@ -15,7 +15,7 @@
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
  */
-#define current_text_addr() ({ void *pc; __asm__("mova	1f,%0\n1:":"=z" (pc)); pc; })
+#define current_text_addr() ({ void *pc; __asm__("mova	1f, %0\n1:":"=z" (pc)); pc; })
 
 /*
  *  CPU type and hardware bug flags. Kept separately for each CPU.
@@ -53,6 +53,15 @@
  */
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
+/*
+ * FPU structure and data
+ */
+/* FD-bit of SR register.
+ * When it's set, it means the processor doesn't have right to use FPU,
+ * and it results exception when the floating operation is executed.
+ */
+#define SR_FD	0x00008000
+
 #define NUM_FPU_REGS	16
 
 struct sh_fpu_hard_struct {
@@ -67,9 +76,9 @@
 /* Dummy fpu emulator  */
 struct sh_fpu_soft_struct {
 	unsigned long fp_regs[NUM_FPU_REGS];
-	unsigned long xf_regs[NUM_FPU_REGS];
 	unsigned long fpscr;
 	unsigned long fpul;
+	unsigned long xf_regs[NUM_FPU_REGS];
 
 	unsigned char	lookahead;
 	unsigned long	entry_pc;
@@ -98,9 +107,9 @@
 #define INIT_THREAD  {						\
 	sizeof(init_stack) + (long) &init_stack, /* sp */	\
 	0,					 /* pc */	\
-	0, 0, \
-	0, \
-	{{{0,}},} \
+	0, 0, 							\
+	0, 							\
+	{{{0,}},} 				/* fpu state */	\
 }
 
 /*
@@ -139,20 +148,19 @@
 #define forget_segments()	do { } while (0)
 
 /*
- * FPU lazy state save handling..
+ * FPU lazy state save handling.
  */
-#define SR_FD	0x00008000
 
 extern __inline__ void release_fpu(void)
 {
 	unsigned long __dummy;
 
 	/* Set FD flag in SR */
-	__asm__ __volatile__ ("stc	sr,%0\n\t"
-			      "or	%1,%0\n\t"
-			      "ldc	%0,sr"
-			      : "=&r" (__dummy)
-			      : "r" (SR_FD));
+	__asm__ __volatile__("stc	$sr, %0\n\t"
+			     "or	%1, %0\n\t"
+			     "ldc	%0, $sr"
+			     : "=&r" (__dummy)
+			     : "r" (SR_FD));
 }
 
 extern __inline__ void grab_fpu(void)
@@ -160,25 +168,25 @@
 	unsigned long __dummy;
 
 	/* Clear out FD flag in SR */
-	__asm__ __volatile__ ("stc	sr,%0\n\t"
-			      "and	%1,%0\n\t"
-			      "ldc	%0,sr"
-			      : "=&r" (__dummy)
-			      : "r" (~SR_FD));
+	__asm__ __volatile__("stc	$sr, %0\n\t"
+			     "and	%1, %0\n\t"
+			     "ldc	%0, $sr"
+			     : "=&r" (__dummy)
+			     : "r" (~SR_FD));
 }
 
 extern void save_fpu(struct task_struct *__tsk);
 
-#define unlazy_fpu(tsk) do { \
-	if (tsk->flags & PF_USEDFPU) \
-		save_fpu(tsk); \
+#define unlazy_fpu(tsk) do { 			\
+	if ((tsk)->flags & PF_USEDFPU) {	\
+		grab_fpu();			\
+		save_fpu(tsk); 			\
+	}					\
 } while (0)
 
-#define clear_fpu(tsk) do { \
-	if (tsk->flags & PF_USEDFPU) { \
-		tsk->flags &= ~PF_USEDFPU; \
-		release_fpu(); \
-	} \
+#define clear_fpu(tsk) do { 			\
+	if ((tsk)->flags & PF_USEDFPU)	 	\
+		(tsk)->flags &= ~PF_USEDFPU; 	\
 } while (0)
 
 /*
@@ -189,13 +197,7 @@
 	return t->pc;
 }
 
-static inline unsigned long get_wchan(struct task_struct *p)
-{
-	if (!p || p == current || p->state == TASK_RUNNING)
-		return 0;
-	/* FIXME: here the actual wchan calculation should sit */
-	return 0;
-}
+extern unsigned long get_wchan(struct task_struct *p);
 
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 #define KSTK_ESP(tsk)  ((tsk)->thread.sp)
@@ -203,6 +205,7 @@
 #define THREAD_SIZE (2*PAGE_SIZE)
 extern struct task_struct * alloc_task_struct(void);
 extern void free_task_struct(struct task_struct *);
+#define get_task_struct(tsk)      atomic_inc(&mem_map[MAP_NR(tsk)].count)
 
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/resource.h linux/include/asm-sh/resource.h
--- v2.3.49/linux/include/asm-sh/resource.h	Tue Dec 14 01:27:24 1999
+++ linux/include/asm-sh/resource.h	Sun Mar  5 09:33:55 2000
@@ -18,13 +18,13 @@
 
 #define RLIM_NLIMITS	10
 
+#ifdef __KERNEL__
+
 /*
  * SuS says limits have to be unsigned.
  * Which makes a ton more sense anyway.
  */
 #define RLIM_INFINITY	(~0UL)
-
-#ifdef __KERNEL__
 
 #define INIT_RLIMITS					\
 {							\
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/scatterlist.h linux/include/asm-sh/scatterlist.h
--- v2.3.49/linux/include/asm-sh/scatterlist.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/scatterlist.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,13 @@
+#ifndef __ASM_SH_SCATTERLIST_H
+#define __ASM_SH_SCATTERLIST_H
+
+struct scatterlist {
+    char *  address;    /* Location data is to be transferred to */
+    char * alt_address; /* Location of actual if address is a 
+			 * dma indirect buffer.  NULL otherwise */
+    unsigned int length;
+};
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* !(__ASM_SH_SCATTERLIST_H) */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/semaphore-helper.h linux/include/asm-sh/semaphore-helper.h
--- v2.3.49/linux/include/asm-sh/semaphore-helper.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/semaphore-helper.h	Sun Mar  5 09:33:55 2000
@@ -16,7 +16,7 @@
  */
 static __inline__ void wake_one_more(struct semaphore * sem)
 {
-	atomic_inc((atomic_t *)&sem->waking);
+	atomic_inc((atomic_t *)&sem->sleepers);
 }
 
 static __inline__ int waking_non_zero(struct semaphore *sem)
@@ -25,8 +25,8 @@
 	int ret = 0;
 
 	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
+	if (sem->sleepers > 0) {
+		sem->sleepers--;
 		ret = 1;
 	}
 	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
@@ -50,8 +50,8 @@
 	int ret = 0;
 
 	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking > 0) {
-		sem->waking--;
+	if (sem->sleepers > 0) {
+		sem->sleepers--;
 		ret = 1;
 	} else if (signal_pending(tsk)) {
 		atomic_inc(&sem->count);
@@ -76,10 +76,10 @@
 	int ret = 1;
 
 	spin_lock_irqsave(&semaphore_wake_lock, flags);
-	if (sem->waking <= 0)
+	if (sem->sleepers <= 0)
 		atomic_inc(&sem->count);
 	else {
-		sem->waking--;
+		sem->sleepers--;
 		ret = 0;
 	}
 	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/semaphore.h linux/include/asm-sh/semaphore.h
--- v2.3.49/linux/include/asm-sh/semaphore.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-sh/semaphore.h	Sun Mar  5 09:33:55 2000
@@ -9,7 +9,7 @@
  * (C) Copyright 1996 Linus Torvalds
  *
  * SuperH verison by Niibe Yutaka
- *
+ *  (Currently no asm implementation but generic C code...)
  */
 
 #include <linux/spinlock.h>
@@ -19,7 +19,7 @@
 
 struct semaphore {
 	atomic_t count;
-	int waking;
+	int sleepers;
 	wait_queue_head_t wait;
 #if WAITQUEUE_DEBUG
 	long __magic;
@@ -55,7 +55,7 @@
  * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
  */
 	atomic_set(&sem->count, val);
-	sem->waking = 0;
+	sem->sleepers = 0;
 	init_waitqueue_head(&sem->wait);
 #if WAITQUEUE_DEBUG
 	sem->__magic = (int)&sem->__magic;
@@ -72,15 +72,20 @@
 	sema_init(sem, 0);
 }
 
+#if 0
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
 asmlinkage int  __down_failed_trylock(void  /* params in registers */);
 asmlinkage void __up_wakeup(void /* special register calling convention */);
+#endif
 
 asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
 asmlinkage int  __down_trylock(struct semaphore * sem);
 asmlinkage void __up(struct semaphore * sem);
+extern struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry);
+extern struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry);
+asmlinkage struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
 
 extern spinlock_t semaphore_wake_lock;
 
@@ -129,6 +134,151 @@
 #endif
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
+}
+
+/* rw mutexes (should that be mutices? =) -- throw rw
+ * spinlocks and semaphores together, and this is what we
+ * end up with...
+ *
+ * SuperH version by Niibe Yutaka
+ */
+struct rw_semaphore {
+	atomic_t		count;
+	volatile unsigned char	write_bias_granted;
+	volatile unsigned char	read_bias_granted;
+	volatile unsigned char	pad1;
+	volatile unsigned char	pad2;
+	wait_queue_head_t	wait;
+	wait_queue_head_t	write_bias_wait;
+#if WAITQUEUE_DEBUG
+	long			__magic;
+	atomic_t		readers;
+	atomic_t		writers;
+#endif
+};
+
+#define RW_LOCK_BIAS		 0x01000000
+
+#if WAITQUEUE_DEBUG
+#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
+	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
+
+extern inline void init_rwsem(struct rw_semaphore *sem)
+{
+	atomic_set(&sem->count, RW_LOCK_BIAS);
+	sem->read_bias_granted = 0;
+	sem->write_bias_granted = 0;
+	init_waitqueue_head(&sem->wait);
+	init_waitqueue_head(&sem->write_bias_wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (long)&sem->__magic;
+	atomic_set(&sem->readers, 0);
+	atomic_set(&sem->writers, 0);
+#endif
+}
+
+extern inline void down_read(struct rw_semaphore *sem)
+{
+	int saved = atomic_read(&sem->count), new;
+#if WAITQUEUE_DEBUG
+	if (sem->__magic != (long)&sem->__magic)
+		BUG();
+#endif
+	if ((new = atomic_dec_return(&sem->count)) < 0)
+		__down_read(sem, (new < 0 && saved >=0));
+#if WAITQUEUE_DEBUG
+	if (sem->write_bias_granted)
+		BUG();
+	if (atomic_read(&sem->writers))
+		BUG();
+	atomic_inc(&sem->readers);
+#endif
+}
+
+extern inline void down_write(struct rw_semaphore *sem)
+{
+	int saved = atomic_read(&sem->count), new;
+#if WAITQUEUE_DEBUG
+	if (sem->__magic != (long)&sem->__magic)
+		BUG();
+#endif
+	if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count)) != 0)
+		__down_write(sem, (new < 0 && saved >=0));
+#if WAITQUEUE_DEBUG
+	if (atomic_read(&sem->writers))
+		BUG();
+	if (atomic_read(&sem->readers))
+		BUG();
+	if (sem->read_bias_granted)
+		BUG();
+	if (sem->write_bias_granted)
+		BUG();
+	atomic_inc(&sem->writers);
+#endif
+}
+
+/* When a reader does a release, the only significant
+ * case is when there was a writer waiting, and we've
+ * bumped the count to 0: we must wake the writer up.
+ */
+extern inline void __up_read(struct rw_semaphore *sem)
+{
+	if (atomic_inc_return(&sem->count) == 0)
+		__rwsem_wake(sem);
+}
+
+/* releasing the writer is easy -- just release it and
+ * wake up any sleepers.
+ */
+extern inline void __up_write(struct rw_semaphore *sem)
+{
+	int saved = atomic_read(&sem->count), new;
+
+	new = atomic_add_return(RW_LOCK_BIAS, &sem->count);
+	if (saved < 0 && new >= 0)
+		__rwsem_wake(sem);
+}
+
+extern inline void up_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	if (sem->write_bias_granted)
+		BUG();
+	if (atomic_read(&sem->writers))
+		BUG();
+	atomic_dec(&sem->readers);
+#endif
+	__up_read(sem);
+}
+
+extern inline void up_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	if (sem->read_bias_granted)
+		BUG();
+	if (sem->write_bias_granted)
+		BUG();
+	if (atomic_read(&sem->readers))
+		BUG();
+	if (atomic_read(&sem->writers) != 1)
+		BUG();
+	atomic_dec(&sem->writers);
+#endif
+	__up_write(sem);
 }
 
 #endif /* __ASM_SH_SEMAPHORE_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/sembuf.h linux/include/asm-sh/sembuf.h
--- v2.3.49/linux/include/asm-sh/sembuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/sembuf.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,25 @@
+#ifndef __ASM_SH_SEMBUF_H
+#define __ASM_SH_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;		/* last semop time */
+	unsigned long	__unused1;
+	__kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	__unused2;
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* __ASM_SH_SEMBUF_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/shmbuf.h linux/include/asm-sh/shmbuf.h
--- v2.3.49/linux/include/asm-sh/shmbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/shmbuf.h	Sun Mar  5 09:33:55 2000
@@ -0,0 +1,42 @@
+#ifndef __ASM_SH_SHMBUF_H
+#define __ASM_SH_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	unsigned long		__unused1;
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	unsigned long		__unused2;
+	__kernel_time_t		shm_ctime;	/* last change time */
+	unsigned long		__unused3;
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* __ASM_SH_SHMBUF_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/siginfo.h linux/include/asm-sh/siginfo.h
--- v2.3.49/linux/include/asm-sh/siginfo.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/siginfo.h	Sun Mar  5 09:33:55 2000
@@ -149,7 +149,7 @@
 #define CLD_TRAPPED	4	/* traced child has trapped */
 #define CLD_STOPPED	5	/* child has stopped */
 #define CLD_CONTINUED	6	/* stopped child has continued */
-#define NSIGCHLD
+#define NSIGCHLD	6
 
 /*
  * SIGPOLL si_codes
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/softirq.h linux/include/asm-sh/softirq.h
--- v2.3.49/linux/include/asm-sh/softirq.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/softirq.h	Sun Mar  5 09:33:55 2000
@@ -1,71 +1,17 @@
 #ifndef __ASM_SH_SOFTIRQ_H
 #define __ASM_SH_SOFTIRQ_H
 
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
 extern unsigned int local_bh_count[NR_CPUS];
 
 #define cpu_bh_disable(cpu)	do { local_bh_count[(cpu)]++; barrier(); } while (0)
 #define cpu_bh_enable(cpu)	do { barrier(); local_bh_count[(cpu)]--; } while (0)
 
-#define cpu_bh_trylock(cpu)	(local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
-#define cpu_bh_endlock(cpu)	(local_bh_count[(cpu)] = 0)
-
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
 
-#define get_active_bhs()	(bh_mask & bh_active)
-#define clear_active_bhs(x)	atomic_clear_mask((x),(atomic_t *)&bh_active)
-
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	atomic_set(&bh_mask_count[nr], 0);
-	bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	mb();
-	bh_base[nr] = NULL;
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-extern inline void start_bh_atomic(void)
-{
-	local_bh_disable();
-	barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
-	barrier();
-	local_bh_enable();
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)	(cpu_bh_trylock(cpu))
-#define softirq_endlock(cpu)	(cpu_bh_endlock(cpu))
-#define synchronize_bh()	barrier()
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	atomic_inc(&bh_mask_count[nr]);
-	synchronize_bh();
-}
-
-extern inline void enable_bh(int nr)
-{
-	if (atomic_dec_and_test(&bh_mask_count[nr]))
-		bh_mask |= 1 << nr;
-}
+#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
 
 #endif /* __ASM_SH_SOFTIRQ_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/stat.h linux/include/asm-sh/stat.h
--- v2.3.49/linux/include/asm-sh/stat.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/stat.h	Sun Mar  5 09:33:55 2000
@@ -38,4 +38,40 @@
 	unsigned long  __unused5;
 };
 
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat64 {
+	unsigned short	st_dev;
+	unsigned char	__pad0[10];
+
+	unsigned long	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	unsigned short	st_rdev;
+	unsigned char	__pad3[10];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+	unsigned long	__pad4;		/* future possible st_blocks high bits */
+
+	unsigned long	st_atime;
+	unsigned long	__pad5;
+
+	unsigned long	st_mtime;
+	unsigned long	__pad6;
+
+	unsigned long	st_ctime;
+	unsigned long	__pad7;		/* will be high 32 bits of ctime someday */
+
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
+
 #endif /* __ASM_SH_STAT_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/system.h linux/include/asm-sh/system.h
--- v2.3.49/linux/include/asm-sh/system.h	Wed Oct 27 16:34:12 1999
+++ linux/include/asm-sh/system.h	Sun Mar  5 09:33:55 2000
@@ -2,7 +2,7 @@
 #define __ASM_SH_SYSTEM_H
 
 /*
- * Copyright (C) 1999  Niibe Yutaka
+ * Copyright (C) 1999, 2000  Niibe Yutaka
  */
 
 /*
@@ -19,44 +19,44 @@
 #define prepare_to_switch()	do { } while(0)
 #define switch_to(prev,next,last) do { \
  register struct task_struct *__last; \
- register unsigned long *__ts1 __asm__ ("r1") = &prev->thread.sp; \
- register unsigned long *__ts2 __asm__ ("r2") = &prev->thread.pc; \
- register unsigned long *__ts4 __asm__ ("r4") = (unsigned long *)prev; \
- register unsigned long *__ts5 __asm__ ("r5") = (unsigned long *)next; \
- register unsigned long *__ts6 __asm__ ("r6") = &next->thread.sp; \
- register unsigned long __ts7 __asm__ ("r7") = next->thread.pc; \
+ register unsigned long *__ts1 __asm__ ("$r1") = &prev->thread.sp; \
+ register unsigned long *__ts2 __asm__ ("$r2") = &prev->thread.pc; \
+ register unsigned long *__ts4 __asm__ ("$r4") = (unsigned long *)prev; \
+ register unsigned long *__ts5 __asm__ ("$r5") = (unsigned long *)next; \
+ register unsigned long *__ts6 __asm__ ("$r6") = &next->thread.sp; \
+ register unsigned long __ts7 __asm__ ("$r7") = next->thread.pc; \
  __asm__ __volatile__ (".balign 4\n\t" \
-		       "stc.l	gbr,@-r15\n\t" \
-		       "sts.l	pr,@-r15\n\t" \
-		       "mov.l	r8,@-r15\n\t" \
-		       "mov.l	r9,@-r15\n\t" \
-		       "mov.l	r10,@-r15\n\t" \
-		       "mov.l	r11,@-r15\n\t" \
-		       "mov.l	r12,@-r15\n\t" \
-		       "mov.l	r13,@-r15\n\t" \
-		       "mov.l	r14,@-r15\n\t" \
-		       "mov.l	r15,@r1		! save SP\n\t" \
-		       "mov.l	@r6,r15		! change to new stack\n\t" \
-		       "mov.l	%0,@-r15	! push R0 onto new stack\n\t" \
-		       "mova	1f,%0\n\t" \
-		       "mov.l	%0,@r2		! save PC\n\t" \
-		       "mov.l	2f,%0\n\t" \
+		       "stc.l	$gbr, @-$r15\n\t" \
+		       "sts.l	$pr, @-$r15\n\t" \
+		       "mov.l	$r8, @-$r15\n\t" \
+		       "mov.l	$r9, @-$r15\n\t" \
+		       "mov.l	$r10, @-$r15\n\t" \
+		       "mov.l	$r11, @-$r15\n\t" \
+		       "mov.l	$r12, @-$r15\n\t" \
+		       "mov.l	$r13, @-$r15\n\t" \
+		       "mov.l	$r14, @-$r15\n\t" \
+		       "mov.l	$r15, @$r1	! save SP\n\t" \
+		       "mov.l	@$r6, $r15	! change to new stack\n\t" \
+		       "mov.l	%0, @-$r15	! push R0 onto new stack\n\t" \
+		       "mova	1f, %0\n\t" \
+		       "mov.l	%0, @$r2	! save PC\n\t" \
+		       "mov.l	2f, %0\n\t" \
 		       "jmp	@%0		! call __switch_to\n\t" \
-		       " lds	r7,pr		!  with return to new PC\n\t" \
+		       " lds	$r7, $pr	!  with return to new PC\n\t" \
 		       ".balign	4\n"	\
 		       "2:\n\t" \
-		       ".long	" "_" "__switch_to\n" \
+		       ".long	" "__switch_to\n" \
 		       "1:\n\t" \
-		       "mov.l	@r15+,%0	! pop R0 from new stack\n\t" \
-		       "mov.l	@r15+,r14\n\t" \
-		       "mov.l	@r15+,r13\n\t" \
-		       "mov.l	@r15+,r12\n\t" \
-		       "mov.l	@r15+,r11\n\t" \
-		       "mov.l	@r15+,r10\n\t" \
-		       "mov.l	@r15+,r9\n\t" \
-		       "mov.l	@r15+,r8\n\t" \
-		       "lds.l	@r15+,pr\n\t" \
-		       "ldc.l	@r15+,gbr\n\t" \
+		       "mov.l	@$r15+, %0	! pop R0 from new stack\n\t" \
+		       "mov.l	@$r15+, $r14\n\t" \
+		       "mov.l	@$r15+, $r13\n\t" \
+		       "mov.l	@$r15+, $r12\n\t" \
+		       "mov.l	@$r15+, $r11\n\t" \
+		       "mov.l	@$r15+, $r10\n\t" \
+		       "mov.l	@$r15+, $r9\n\t" \
+		       "mov.l	@$r15+, $r8\n\t" \
+		       "lds.l	@$r15+, $pr\n\t" \
+		       "ldc.l	@$r15+, $gbr\n\t" \
 		       :"=&z" (__last) \
 		       :"0" (prev), \
 			"r" (__ts1), "r" (__ts2), \
@@ -95,9 +95,9 @@
 {
 	unsigned long __dummy;
 
-	__asm__ __volatile__("stc	sr,%0\n\t"
-			     "and	%1,%0\n\t"
-			     "ldc	%0,sr"
+	__asm__ __volatile__("stc	$sr, %0\n\t"
+			     "and	%1, %0\n\t"
+			     "ldc	%0, $sr"
 			     : "=&r" (__dummy)
 			     : "r" (0xefffffff)
 			     : "memory");
@@ -106,30 +106,46 @@
 extern __inline__ void __cli(void)
 {
 	unsigned long __dummy;
-	__asm__ __volatile__("stc	sr,%0\n\t"
-			     "or	%1,%0\n\t"
-			     "ldc	%0,sr"
+	__asm__ __volatile__("stc	$sr, %0\n\t"
+			     "or	%1, %0\n\t"
+			     "ldc	%0, $sr"
 			     : "=&r" (__dummy)
 			     : "r" (0x10000000)
 			     : "memory");
 }
 
-#define __save_flags(x) \
-__asm__ __volatile__("stc	sr,%0":"=r" (x): /* no inputs */ :"memory")
+#define __save_flags(x) 			\
+x = (__extension__ ({	unsigned long __sr;	\
+	__asm__ __volatile__(			\
+		"stc	$sr, %0"		\
+		: "=r" (__sr)			\
+		: /* no inputs */		\
+		: "memory");			\
+	 (__sr & 0xffff7f0f);}))
 
 #define __save_and_cli(x)    				\
 x = (__extension__ ({	unsigned long __dummy,__sr;	\
 	__asm__ __volatile__(                   	\
-		"stc	sr,%1\n\t" 			\
-		"or	%0,%1\n\t" 			\
-		"stc	sr,%0\n\t" 			\
-		"ldc	%1,sr"     			\
+		"stc	$sr, %1\n\t" 			\
+		"or	%0, %1\n\t" 			\
+		"stc	$sr, %0\n\t" 			\
+		"ldc	%1, $sr"     			\
 		: "=r" (__sr), "=&r" (__dummy) 		\
 		: "0" (0x10000000) 			\
-		: "memory"); __sr; }))
+		: "memory"); (__sr & 0xffff7f0f); }))
 
-#define __restore_flags(x) \
-__asm__ __volatile__("ldc	%0,sr": /* no output */: "r" (x):"memory")
+#define __restore_flags(x) do { 			\
+	unsigned long __dummy;				\
+	__asm__ __volatile__(				\
+		"stc	$sr, %0\n\t"			\
+		"and	%1, %0\n\t"			\
+		"or	%2, %0\n\t"			\
+		"ldc	%0, $sr"			\
+		: "=&r" (__dummy)			\
+		: "r" (0x000080f0), /* IMASK+FD */	\
+		  "r" (x)		 		\
+		: "memory"); 				\
+} while (0)
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
@@ -169,11 +185,25 @@
 	return retval;
 }
 
+extern __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val)
+{
+	unsigned long flags, retval;
+
+	save_and_cli(flags);
+	retval = *m;
+	*m = val & 0xff;
+	restore_flags(flags);
+	return retval;
+}
+
 static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 {
 	switch (size) {
 	case 4:
 		return xchg_u32(ptr, x);
+		break;
+	case 1:
+		return xchg_u8(ptr, x);
 		break;
 	}
 	__xchg_called_with_bad_pointer();
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/termios.h linux/include/asm-sh/termios.h
--- v2.3.49/linux/include/asm-sh/termios.h	Mon Nov  1 13:56:27 1999
+++ linux/include/asm-sh/termios.h	Sun Mar  5 09:33:55 2000
@@ -35,6 +35,7 @@
 #define TIOCM_RI	TIOCM_RNG
 #define TIOCM_OUT1	0x2000
 #define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/types.h linux/include/asm-sh/types.h
--- v2.3.49/linux/include/asm-sh/types.h	Fri Oct 22 13:21:55 1999
+++ linux/include/asm-sh/types.h	Sun Mar  5 09:33:55 2000
@@ -41,6 +41,10 @@
 
 #define BITS_PER_LONG 32
 
+/* Dma addresses are 32-bits wide.  */
+
+typedef u32 dma_addr_t;
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_SH_TYPES_H */
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/unistd.h linux/include/asm-sh/unistd.h
--- v2.3.49/linux/include/asm-sh/unistd.h	Fri Oct 22 13:21:55 1999
+++ linux/include/asm-sh/unistd.h	Sun Mar  5 09:33:55 2000
@@ -31,7 +31,7 @@
 #define __NR_lseek		 19
 #define __NR_getpid		 20
 #define __NR_mount		 21
-#define __NR_oldumount		 22
+#define __NR_umount		 22
 #define __NR_setuid		 23
 #define __NR_getuid		 24
 #define __NR_stime		 25
@@ -61,7 +61,7 @@
 #define __NR_geteuid		 49
 #define __NR_getegid		 50
 #define __NR_acct		 51
-#define __NR_umount		 52
+#define __NR_umount2		 52
 #define __NR_lock		 53
 #define __NR_ioctl		 54
 #define __NR_fcntl		 55
@@ -85,7 +85,7 @@
 #define __NR_sigpending		 73
 #define __NR_sethostname	 74
 #define __NR_setrlimit		 75
-#define __NR_getrlimit		 76
+#define __NR_getrlimit	 	 76	/* Back compatible 2Gig limited rlimit */
 #define __NR_getrusage		 77
 #define __NR_gettimeofday	 78
 #define __NR_settimeofday	 79
@@ -200,6 +200,33 @@
 #define __NR_streams1		188	/* some people actually want it */
 #define __NR_streams2		189	/* some people actually want it */
 #define __NR_vfork		190
+#define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
+#define __NR_mmap2		192
+#define __NR_truncate64		193
+#define __NR_ftruncate64	194
+#define __NR_stat64		195
+#define __NR_lstat64		196
+#define __NR_fstat64		197
+#define __NR_lchown32		198
+#define __NR_getuid32		199
+#define __NR_getgid32		200
+#define __NR_geteuid32		201
+#define __NR_getegid32		202
+#define __NR_setreuid32		203
+#define __NR_setregid32		204
+#define __NR_getgroups32	205
+#define __NR_setgroups32	206
+#define __NR_fchown32		207
+#define __NR_setresuid32	208
+#define __NR_getresuid32	209
+#define __NR_setresgid32	210
+#define __NR_getresgid32	211
+#define __NR_chown32		212
+#define __NR_setuid32		213
+#define __NR_setgid32		214
+#define __NR_setfsuid32		215
+#define __NR_setfsgid32		216
+#define __NR_pivot_root		217
 
 /* user-visible error numbers are in the range -1 - -125: see <asm-sh/errno.h> */
 
@@ -219,7 +246,7 @@
 #define _syscall0(type,name) \
 type name(void) \
 { \
-register long __sc0 __asm__ ("r0") = __NR_##name; \
+register long __sc0 __asm__ ("$r0") = __NR_##name; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
 	: "0" (__sc0) \
@@ -230,8 +257,8 @@
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
 { \
-register long __sc0 __asm__ ("r0") = __NR_##name; \
-register long __sc4 __asm__ ("r4") = (long) arg1; \
+register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc4 __asm__ ("$r4") = (long) arg1; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4) \
@@ -242,9 +269,9 @@
 #define _syscall2(type,name,type1,arg1,type2,arg2) \
 type name(type1 arg1,type2 arg2) \
 { \
-register long __sc0 __asm__ ("r0") = __NR_##name; \
-register long __sc4 __asm__ ("r4") = (long) arg1; \
-register long __sc5 __asm__ ("r5") = (long) arg2; \
+register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc4 __asm__ ("$r4") = (long) arg1; \
+register long __sc5 __asm__ ("$r5") = (long) arg2; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5) \
@@ -255,10 +282,10 @@
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
 type name(type1 arg1,type2 arg2,type3 arg3) \
 { \
-register long __sc0 __asm__ ("r0") = __NR_##name; \
-register long __sc4 __asm__ ("r4") = (long) arg1; \
-register long __sc5 __asm__ ("r5") = (long) arg2; \
-register long __sc6 __asm__ ("r6") = (long) arg3; \
+register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc4 __asm__ ("$r4") = (long) arg1; \
+register long __sc5 __asm__ ("$r5") = (long) arg2; \
+register long __sc6 __asm__ ("$r6") = (long) arg3; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \
@@ -269,15 +296,32 @@
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
 { \
-register long __sc0 __asm__ ("r0") = __NR_##name; \
-register long __sc4 __asm__ ("r4") = (long) arg1; \
-register long __sc5 __asm__ ("r5") = (long) arg2; \
-register long __sc6 __asm__ ("r6") = (long) arg3; \
-register long __sc6 __asm__ ("r7") = (long) arg4; \
+register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc4 __asm__ ("$r4") = (long) arg1; \
+register long __sc5 __asm__ ("$r5") = (long) arg2; \
+register long __sc6 __asm__ ("$r6") = (long) arg3; \
+register long __sc7 __asm__ ("$r7") = (long) arg4; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6),  \
 	  "r" (__sc7) \
+	: "memory" ); \
+__syscall_return(type,__sc0); \
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
+{ \
+register long __sc0 __asm__ ("$r0") = __NR_##name; \
+register long __sc4 __asm__ ("$r4") = (long) arg1; \
+register long __sc5 __asm__ ("$r5") = (long) arg2; \
+register long __sc6 __asm__ ("$r6") = (long) arg3; \
+register long __sc7 __asm__ ("$r7") = (long) arg4; \
+__asm__ __volatile__ ("mov.l	%2, @-$r15\n\t" \
+		      "trapa	#0" \
+	: "=z" (__sc0) \
+	: "0" (__sc0), "r" (arg5), \
+	  "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7) \
 	: "memory" ); \
 __syscall_return(type,__sc0); \
 }
diff -u --recursive --new-file v2.3.49/linux/include/asm-sh/user.h linux/include/asm-sh/user.h
--- v2.3.49/linux/include/asm-sh/user.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/user.h	Sun Mar  5 09:33:55 2000
@@ -2,6 +2,7 @@
 #define __ASM_SH_USER_H
 
 #include <linux/types.h>
+#include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/page.h>
 
@@ -27,8 +28,18 @@
  *	current->start_stack, so we round each of these in order to be able
  *	to write an integer number of pages.
  */
+
+struct user_fpu_struct {
+	unsigned long fp_regs[NUM_FPU_REGS];
+	unsigned long xf_regs[NUM_FPU_REGS];
+	unsigned long fpscr;
+	unsigned long fpul;
+};
+
 struct user {
 	struct pt_regs	regs;			/* entire machine state */
+	struct user_fpu_struct fpu;	/* Math Co-processor registers. */
+	int u_fpvalid;		/* True if math co-processor being used. */
 	size_t		u_tsize;		/* text size (pages) */
 	size_t		u_dsize;		/* data size (pages) */
 	size_t		u_ssize;		/* stack size (pages) */
@@ -37,6 +48,7 @@
 	unsigned long	start_stack;		/* stack starting address */
 	long int	signal;			/* signal causing core dump */
 	struct regs *	u_ar0;			/* help gdb find registers */
+	struct user_fpu_struct* u_fpstate;	/* Math Co-processor pointer. */
 	unsigned long	magic;			/* identifies a core file */
 	char		u_comm[32];		/* user command name */
 };
diff -u --recursive --new-file v2.3.49/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.3.49/linux/include/asm-sparc/pgtable.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-sparc/pgtable.h	Tue Mar  7 11:10:54 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.91 2000/02/16 08:44:52 anton Exp $ */
+/* $Id: pgtable.h,v 1.92 2000/03/02 20:37:37 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
diff -u --recursive --new-file v2.3.49/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.49/linux/include/asm-sparc64/pgtable.h	Thu Mar  2 14:36:23 2000
+++ linux/include/asm-sparc64/pgtable.h	Tue Mar  7 11:10:54 2000
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.120 2000/02/16 07:34:54 davem Exp $
+/* $Id: pgtable.h,v 1.121 2000/03/02 20:37:41 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.49/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.3.49/linux/include/asm-sparc64/system.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-sparc64/system.h	Tue Mar  7 11:05:48 2000
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.55 1999/09/10 10:44:44 davem Exp $ */
+/* $Id: system.h,v 1.56 2000/03/06 22:33:45 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -116,7 +116,16 @@
 #define read_pcr(__p)  __asm__ __volatile__("rd	%%pcr, %0" : "=r" (__p))
 #define write_pcr(__p) __asm__ __volatile__("wr	%0, 0x0, %%pcr" : : "r" (__p));
 #define read_pic(__p)  __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
-#define reset_pic()    __asm__ __volatile__("wr	%g0, 0x0, %pic");
+
+/* Blackbird errata workaround.  See commentary in
+ * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
+ * for more information.
+ */
+#define reset_pic()    						\
+	__asm__ __volatile__("ba,pt	%xcc, 99f\n\t"		\
+			     ".align	64\n"			\
+			  "99:wr	%g0, 0x0, %pic\n\t"	\
+			     "rd	%pic, %g0")
 
 #ifndef __ASSEMBLY__
 
diff -u --recursive --new-file v2.3.49/linux/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h
--- v2.3.49/linux/include/linux/ac97_codec.h	Thu Mar  2 14:36:23 2000
+++ linux/include/linux/ac97_codec.h	Thu Mar  2 22:44:07 2000
@@ -54,14 +54,13 @@
 /* record mux defines */
 #define AC97_RECMUX_MIC           0x0000
 #define AC97_RECMUX_CD            0x0101
-#define AC97_RECMUX_VIDEO         0x0202       /* not used */
-#define AC97_RECMUX_AUX           0x0303      
-#define AC97_RECMUX_LINE          0x0404      
+#define AC97_RECMUX_VIDEO         0x0202
+#define AC97_RECMUX_AUX           0x0303
+#define AC97_RECMUX_LINE          0x0404
 #define AC97_RECMUX_STEREO_MIX    0x0505
 #define AC97_RECMUX_MONO_MIX      0x0606
 #define AC97_RECMUX_PHONE         0x0707
 
-
 /* general purpose register bit defines */
 #define AC97_GP_LPBK              0x0080       /* Loopback mode */
 #define AC97_GP_MS                0x0100       /* Mic Select 0=Mic1, 1=Mic2 */
@@ -73,7 +72,6 @@
 #define AC97_GP_ST                0x4000       /* Stereo Enhancement 1=on */
 #define AC97_GP_POP               0x8000       /* Pcm Out Path, 0=pre 3D, 1=post 3D */
 
-
 /* powerdown control and status bit defines */
 
 /* status */
@@ -116,7 +114,7 @@
 	SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT)
 
 #define AC97_RECORD_MASK (SOUND_MASK_MIC|\
-	SOUND_MASK_CD|SOUND_MASK_VIDEO|\
+	SOUND_MASK_CD|SOUND_MASK_IGAIN|SOUND_MASK_VIDEO|\
 	SOUND_MASK_LINE1| SOUND_MASK_LINE|\
 	SOUND_MASK_PHONEIN)
 
diff -u --recursive --new-file v2.3.49/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.3.49/linux/include/linux/cdrom.h	Wed Feb 16 17:03:52 2000
+++ linux/include/linux/cdrom.h	Tue Mar  7 11:25:14 2000
@@ -5,13 +5,12 @@
  *               1994, 1995   Eberhard Moenkeberg, emoenke@gwdg.de
  *               1996         David van Leeuwen, david@tm.tno.nl
  *               1997, 1998   Erik Andersen, andersee@debian.org
- *               1998, 1999   Jens Axboe, axboe@image.dk
+ *               1998-2000    Jens Axboe, axboe@suse.de
  */
  
 #ifndef	_LINUX_CDROM_H
 #define	_LINUX_CDROM_H
 
-#include <linux/types.h>
 #include <asm/byteorder.h>
 
 /*******************************************************
@@ -225,7 +224,7 @@
 struct cdrom_read      
 {
 	int	cdread_lba;
-	caddr_t	cdread_bufaddr;
+	char 	*cdread_bufaddr;
 	int	cdread_buflen;
 };
 
@@ -267,6 +266,11 @@
 
 #define CDROM_PACKET_SIZE	12
 
+#define CGC_DATA_UNKNOWN	0
+#define CGC_DATA_WRITE		1
+#define CGC_DATA_READ		2
+#define CGC_DATA_NONE		3
+
 /* for CDROM_PACKET_COMMAND ioctl */
 struct cdrom_generic_command
 {
@@ -275,6 +279,7 @@
 	unsigned int 		buflen;
 	int			stat;
 	struct request_sense	*sense;
+	unsigned char		data_direction;
 	void			*reserved[3];
 };
 
@@ -790,7 +795,8 @@
 			    struct cdrom_generic_command *cgc,
 			    int page_code, int page_control);
 extern void init_cdrom_command(struct cdrom_generic_command *cgc,
-			       void *buffer, int len);
+			       void *buffer, int len, int type);
+extern struct cdrom_device_info *cdrom_find_device(kdev_t dev);
 
 typedef struct {
 	__u16 disc_information_length;
@@ -798,9 +804,9 @@
 	__u8 reserved1			: 3;
         __u8 erasable			: 1;
         __u8 border_status		: 2;
-        __u8 disc_border		: 2;
+        __u8 disc_status		: 2;
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
-        __u8 disc_border		: 2;
+        __u8 disc_status		: 2;
         __u8 border_status		: 2;
         __u8 erasable			: 1;
 	__u8 reserved1			: 3;
@@ -938,7 +944,6 @@
 };
 
 typedef struct {
-	struct mode_page_header header;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 ps			: 1;
 	__u8 reserved1		: 1;
@@ -991,7 +996,7 @@
 	__u8 subhdr1;
 	__u8 subhdr2;
 	__u8 subhdr3;
-} write_param_page __attribute__((packed));
+} __attribute__((packed)) write_param_page;
 
 #endif  /* End of kernel only stuff */ 
 
diff -u --recursive --new-file v2.3.49/linux/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- v2.3.49/linux/include/linux/devfs_fs_kernel.h	Wed Feb 16 17:03:52 2000
+++ linux/include/linux/devfs_fs_kernel.h	Tue Mar  7 11:25:14 2000
@@ -16,22 +16,26 @@
       ) ? m : MINOR((inode)->r_dev); })
 
 
-#define DEVFS_FL_NONE         0x000  /* This helps making code more readable */
-#define DEVFS_FL_AUTO_OWNER   0x001  /* When a closed inode is opened the
-					ownerships are set to the opening
-					process and the protection is set to
-					that given in <<mode>>. When the inode
-					is closed, ownership reverts back to
-					<<uid>> and <<gid>> and the protection
-					is set to read-write for all         */
-#define DEVFS_FL_SHOW_UNREG   0x002  /* Show unregistered entries in
-					directory listings                   */
-#define DEVFS_FL_HIDE         0x004  /* Do not show entry in directory list  */
-#define DEVFS_FL_AUTO_DEVNUM  0x008  /* Automatically generate device number */
-#define DEVFS_FL_AOPEN_NOTIFY 0x010  /* Asynchronously notify devfsd on open */
-#define DEVFS_FL_REMOVABLE    0x020  /* This is a removable media device     */
-#define DEVFS_FL_WAIT         0x040  /* Wait for devfsd to finish            */
-#define DEVFS_FL_DEFAULT      DEVFS_FL_NONE
+#define DEVFS_FL_NONE           0x000 /* This helps to make code more readable
+				       */
+#define DEVFS_FL_AUTO_OWNER     0x001 /* When a closed inode is opened the
+					 ownerships are set to the opening
+					 process and the protection is set to
+					 that given in <<mode>>. When the inode
+					 is closed, ownership reverts back to
+					 <<uid>> and <<gid>> and the protection
+					 is set to read-write for all        */
+#define DEVFS_FL_SHOW_UNREG     0x002 /* Show unregistered entries in
+					 directory listings                  */
+#define DEVFS_FL_HIDE           0x004 /* Do not show entry in directory list */
+#define DEVFS_FL_AUTO_DEVNUM    0x008 /* Automatically generate device number
+				       */
+#define DEVFS_FL_AOPEN_NOTIFY   0x010 /* Asynchronously notify devfsd on open
+				       */
+#define DEVFS_FL_REMOVABLE      0x020 /* This is a removable media device    */
+#define DEVFS_FL_WAIT           0x040 /* Wait for devfsd to finish           */
+#define DEVFS_FL_NO_PERSISTENCE 0x080 /* Forget changes after unregister     */
+#define DEVFS_FL_DEFAULT        DEVFS_FL_NONE
 
 
 #define DEVFS_SPECIAL_CHR     0
diff -u --recursive --new-file v2.3.49/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.49/linux/include/linux/fs.h	Sat Feb 26 22:32:06 2000
+++ linux/include/linux/fs.h	Tue Mar  7 11:25:12 2000
@@ -630,6 +630,11 @@
 /*
  * VFS helper functions..
  */
+extern int vfs_create(struct inode *, struct dentry *, int);
+extern int vfs_mkdir(struct inode *, struct dentry *, int);
+extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
+extern int vfs_symlink(struct inode *, struct dentry *, const char *);
+extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
 extern int vfs_rmdir(struct inode *, struct dentry *);
 extern int vfs_unlink(struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
@@ -1027,6 +1032,8 @@
 extern int page_readlink(struct dentry *, char *, int);
 extern struct dentry *page_follow_link(struct dentry *, struct dentry *, unsigned);
 extern struct inode_operations page_symlink_inode_operations;
+
+extern int vfs_readdir(struct file *, filldir_t, void *);
 
 extern struct super_block *get_super(kdev_t);
 struct super_block *get_empty_super(void);
diff -u --recursive --new-file v2.3.49/linux/include/linux/i2c-id.h linux/include/linux/i2c-id.h
--- v2.3.49/linux/include/linux/i2c-id.h	Sun Feb 13 19:29:04 2000
+++ linux/include/linux/i2c-id.h	Sun Mar  5 09:35:07 2000
@@ -69,6 +69,7 @@
 #define I2C_DRIVERID_MGATVO	23	/* Matrox TVOut			*/
 #define I2C_DRIVERID_SAA5249	24	/* SAA5249 and compatibles	*/
 #define I2C_DRIVERID_PCF8583	25	/* real time clock		*/
+#define I2C_DRIVERID_SAB3036	26	/* SAB3036 tuner		*/
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
 #define I2C_DRIVERID_EXP1	0xF1
diff -u --recursive --new-file v2.3.49/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.49/linux/include/linux/ide.h	Sat Feb 26 22:32:06 2000
+++ linux/include/linux/ide.h	Tue Mar  7 11:25:36 2000
@@ -358,7 +358,8 @@
 		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
 		ide_qd6580,	ide_umc8672,	ide_ht6560b,
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
-		ide_cmd646,	ide_cy82c693,	ide_4drives
+		ide_cmd646,	ide_cy82c693,	ide_4drives,
+		ide_pmac
 } hwif_chipset_t;
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
diff -u --recursive --new-file v2.3.49/linux/include/linux/linkage.h linux/include/linux/linkage.h
--- v2.3.49/linux/include/linux/linkage.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/linkage.h	Sun Mar  5 09:33:55 2000
@@ -15,24 +15,12 @@
 #define asmlinkage CPP_ASMLINKAGE
 #endif
 
-#ifdef __sh__
-#define STRINGIFY(X) #X
-#define SYMBOL_NAME_STR(X) STRINGIFY(SYMBOL_NAME(X))
-#ifdef __STDC__
-#define SYMBOL_NAME(X) _##X
-#define SYMBOL_NAME_LABEL(X) _##X##:
-#else
-#define SYMBOL_NAME(X) _/**/X
-#define SYMBOL_NAME_LABEL(X) _/**/X/**/:
-#endif
-#else
 #define SYMBOL_NAME_STR(X) #X
 #define SYMBOL_NAME(X) X
 #ifdef __STDC__
 #define SYMBOL_NAME_LABEL(X) X##:
 #else
 #define SYMBOL_NAME_LABEL(X) X/**/:
-#endif
 #endif
 
 #ifdef __arm__
diff -u --recursive --new-file v2.3.49/linux/include/linux/netfilter.h linux/include/linux/netfilter.h
--- v2.3.49/linux/include/linux/netfilter.h	Thu Mar  2 14:36:23 2000
+++ linux/include/linux/netfilter.h	Tue Mar  7 11:29:46 2000
@@ -179,7 +179,6 @@
 	NF_REASON_SET_BY_IPCHAINS,
 	NF_REASON_FOR_ROUTING,
 	NF_REASON_FOR_CLS_FW,
-	NF_REASON_MIN_RESERVED_FOR_CONNTRACK = 1024,
 };
 
 #endif /*__LINUX_NETFILTER_H*/
diff -u --recursive --new-file v2.3.49/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.3.49/linux/include/linux/skbuff.h	Sun Feb 20 21:12:40 2000
+++ linux/include/linux/skbuff.h	Tue Mar  7 11:25:14 2000
@@ -37,6 +37,17 @@
 #define NET_CALLER(arg) __builtin_return_address(0)
 #endif
 
+#ifdef CONFIG_NETFILTER
+struct nf_conntrack {
+	atomic_t use;
+	void (*destroy)(struct nf_conntrack *);
+};
+
+struct nf_ct_info {
+	struct nf_conntrack *master;
+};
+#endif
+
 struct sk_buff_head {
 	/* These two members must be first. */
 	struct sk_buff	* next;
@@ -115,6 +126,8 @@
 	__u32		nfreason;
 	/* Cache info */
 	__u32		nfcache;
+	/* Associated connection, if any */
+	struct nf_ct_info *nfct;
 #ifdef CONFIG_NETFILTER_DEBUG
         unsigned int nf_debug;
 #endif
@@ -634,6 +647,21 @@
 
 extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
+
+#ifdef CONFIG_NETFILTER
+extern __inline__ void
+nf_conntrack_put(struct nf_ct_info *nfct)
+{
+	if (nfct && atomic_dec_and_test(&nfct->master->use))
+		nfct->master->destroy(nfct->master);
+}
+extern __inline__ void
+nf_conntrack_get(struct nf_ct_info *nfct)
+{
+	if (nfct)
+		atomic_inc(&nfct->master->use);
+}
+#endif
 
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_SKBUFF_H */
diff -u --recursive --new-file v2.3.49/linux/include/linux/zorro.h linux/include/linux/zorro.h
--- v2.3.49/linux/include/linux/zorro.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/zorro.h	Tue Mar  7 10:52:41 2000
@@ -717,7 +717,6 @@
      */
 
 extern void zorro_init(void);
-extern void zorro_proc_init(void);
 
 extern struct zorro_dev *zorro_find_device(zorro_id id,
 					   struct zorro_dev *from);
diff -u --recursive --new-file v2.3.49/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.3.49/linux/include/scsi/sg.h	Thu Feb 10 17:11:23 2000
+++ linux/include/scsi/sg.h	Tue Mar  7 10:57:47 2000
@@ -9,11 +9,15 @@
 Original driver (sg.h):
 *       Copyright (C) 1992 Lawrence Foard
 Version 2 and 3 extensions to driver:
-*       Copyright (C) 1998, 1999 Douglas Gilbert
+*       Copyright (C) 1998 - 2000 Douglas Gilbert
 
-    Version: 3.1.10 (20000123)
+    Version: 3.1.12 (20000222)
     This version is for 2.3/2.4 series kernels.
 
+    Changes since 3.1.10 (20000123)
+    	- make device allocation dynamic (get rid of SG_EXTRA_DEVS)
+	- move to sg0,sg1,sg2 rather than sga,sgb,sgc
+	- make sg_io_hdr_t safer across architectures
     Changes since 2.1.34 (990603) and 2.3.35 (990708)
 	- add new interface structure: sg_io_hdr_t
 	  - supports larger sense buffer, DMA residual count + direct IO
@@ -110,11 +114,11 @@
 
 typedef struct sg_io_hdr
 {
-    char interface_id;          /* [i] 'S' for SCSI generic (required) */
+    int interface_id;           /* [i] 'S' for SCSI generic (required) */
+    int dxfer_direction;        /* [i] data transfer direction  */
     unsigned char cmd_len;      /* [i] SCSI command length ( <= 16 bytes) */
-    unsigned char iovec_count;  /* [i] 0 implies no scatter gather */
     unsigned char mx_sb_len;    /* [i] max length to write to sbp */
-    int dxfer_direction;        /* [i] data transfer direction  */
+    unsigned short iovec_count; /* [i] 0 implies no scatter gather */
     unsigned int dxfer_len;     /* [i] byte count of data transfer */
     void * dxferp;              /* [i], [*io] points to data transfer memory
 					      or scatter gather list */
@@ -133,7 +137,7 @@
     int resid;                  /* [o] dxfer_len - actual_transferred */
     unsigned int duration;      /* [o] time taken by cmd (unit: millisec) */
     unsigned int info;          /* [o] auxiliary information */
-} sg_io_hdr_t;  /* 60 bytes long (on i386) */
+} sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
 /* Use negative values to flag difference from original sg_header structure */
 #define SG_DXFER_NONE -1        /* e.g. a SCSI Test Unit Ready command */
@@ -223,9 +227,13 @@
 
 #define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
 
-/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
-   1 -> device reset or  2 -> bus reset (may not be activated yet) */
+/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
 #define SG_SCSI_RESET 0x2284
+/* Associated values that can be given to SG_SCSI_RESET follow */
+#define		SG_SCSI_RESET_NOTHING	0
+#define		SG_SCSI_RESET_DEVICE	1
+#define		SG_SCSI_RESET_BUS	2
+#define		SG_SCSI_RESET_HOST	3
 
 /* synchronous SCSI command ioctl, (only in version 3 interface) */
 #define SG_IO 0x2285   /* similar effect as write() followed by read() */
@@ -291,7 +299,7 @@
 
 
 /* IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t
-	   interface is used. That are kept for backward compatibility with
+	   interface is used. They are kept for backward compatibility with
 	   the original and version 2 drivers. */
 
 #define SG_SET_TIMEOUT 0x2201  /* unit: jiffies (10ms on i386) */
diff -u --recursive --new-file v2.3.49/linux/include/video/fbcon-hga.h linux/include/video/fbcon-hga.h
--- v2.3.49/linux/include/video/fbcon-hga.h	Wed Dec 31 16:00:00 1969
+++ linux/include/video/fbcon-hga.h	Tue Mar  7 11:06:44 2000
@@ -0,0 +1,32 @@
+/*
+ *  FBcon low-level driver for Hercules Graphics Adaptor (hga)
+ */
+
+#ifndef _VIDEO_FBCON_HGA_H
+#define _VIDEO_FBCON_HGA_H
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#if defined(CONFIG_FBCON_HGA) || defined(CONFIG_FBCON_HGA_MODULE)
+#define FBCON_HAS_HGA
+#endif
+#else
+#if defined(CONFIG_FBCON_HGA)
+#define FBCON_HAS_HGA
+#endif
+#endif
+
+extern struct display_switch fbcon_hga;
+extern void fbcon_hga_setup(struct display *p);
+extern void fbcon_hga_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			    int height, int width);
+extern void fbcon_hga_clear(struct vc_data *conp, struct display *p, int sy,
+			    int sx, int height, int width);
+extern void fbcon_hga_putc(struct vc_data *conp, struct display *p, int c,
+			   int yy, int xx);
+extern void fbcon_hga_putcs(struct vc_data *conp, struct display *p,
+			    const unsigned short *s, int count, int yy, int xx);
+extern void fbcon_hga_revc(struct display *p, int xx, int yy);
+
+#endif /* _VIDEO_FBCON_HGA_H */
diff -u --recursive --new-file v2.3.49/linux/ipc/sem.c linux/ipc/sem.c
--- v2.3.49/linux/ipc/sem.c	Fri Jan 21 18:19:17 2000
+++ linux/ipc/sem.c	Tue Mar  7 13:11:01 2000
@@ -309,7 +309,7 @@
 	for (q = sma->sem_pending; q; q = q->next) {
 			
 		if (q->status == 1)
-			return; /* wait for other process */
+			continue;	/* this one was woken up before */
 
 		error = try_atomic_semop(sma, q->sops, q->nsops,
 					 q->undo, q->pid, q->alter);
diff -u --recursive --new-file v2.3.49/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.49/linux/ipc/shm.c	Sat Feb 26 22:32:07 2000
+++ linux/ipc/shm.c	Thu Mar  2 17:30:33 2000
@@ -925,9 +925,9 @@
 			swap_free(entry);
 			if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
 				BUG();
-			if (is_shmzero) shm_swp--;
+			if (is_shmzero == 0) shm_swp--;
 		}
-		if (is_shmzero) shm_rss++;
+		if (is_shmzero == 0) shm_rss++;
 		pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
 		SHM_ENTRY(shp, idx) = pte;
 	} else
diff -u --recursive --new-file v2.3.49/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.49/linux/kernel/ksyms.c	Thu Mar  2 14:36:23 2000
+++ linux/kernel/ksyms.c	Tue Mar  7 11:24:19 2000
@@ -182,6 +182,7 @@
 EXPORT_SYMBOL(get_hardblocksize);
 EXPORT_SYMBOL(set_blocksize);
 EXPORT_SYMBOL(getblk);
+EXPORT_SYMBOL(bdget);
 EXPORT_SYMBOL(bread);
 EXPORT_SYMBOL(breada);
 EXPORT_SYMBOL(__brelse);
@@ -217,6 +218,11 @@
 EXPORT_SYMBOL(find_inode_number);
 EXPORT_SYMBOL(is_subdir);
 EXPORT_SYMBOL(get_unused_fd);
+EXPORT_SYMBOL(vfs_create);
+EXPORT_SYMBOL(vfs_mkdir);
+EXPORT_SYMBOL(vfs_mknod);
+EXPORT_SYMBOL(vfs_symlink);
+EXPORT_SYMBOL(vfs_link);
 EXPORT_SYMBOL(vfs_rmdir);
 EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(vfs_rename);
@@ -233,6 +239,7 @@
 EXPORT_SYMBOL(page_follow_link);
 EXPORT_SYMBOL(page_symlink_inode_operations);
 EXPORT_SYMBOL(block_symlink);
+EXPORT_SYMBOL(vfs_readdir);
 
 /* for stackable file systems (lofs, wrapfs, etc.) */
 EXPORT_SYMBOL(add_to_page_cache);
@@ -368,6 +375,7 @@
 EXPORT_SYMBOL(request_resource);
 EXPORT_SYMBOL(release_resource);
 EXPORT_SYMBOL(allocate_resource);
+EXPORT_SYMBOL(check_resource);
 EXPORT_SYMBOL(__request_region);
 EXPORT_SYMBOL(__check_region);
 EXPORT_SYMBOL(__release_region);
diff -u --recursive --new-file v2.3.49/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.3.49/linux/kernel/softirq.c	Thu Feb 10 17:11:23 2000
+++ linux/kernel/softirq.c	Sat Mar  4 17:37:51 2000
@@ -204,6 +204,7 @@
 		schedule();
 	}
 	tasklet_unlock_wait(t);
+	clear_bit(TASKLET_STATE_SCHED, &t->state);
 }
 
 
diff -u --recursive --new-file v2.3.49/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.49/linux/mm/page_alloc.c	Thu Mar  2 14:36:23 2000
+++ linux/mm/page_alloc.c	Mon Mar  6 14:30:56 2000
@@ -82,6 +82,8 @@
 	if (PageReserved(page))
 		return;
 
+	if (page->buffers)
+		BUG();
 	if (page-mem_map >= max_mapnr)
 		BUG();
 	if (PageSwapCache(page))
diff -u --recursive --new-file v2.3.49/linux/net/Config.in linux/net/Config.in
--- v2.3.49/linux/net/Config.in	Sun Feb 20 21:12:40 2000
+++ linux/net/Config.in	Fri Mar  3 12:54:44 2000
@@ -53,7 +53,7 @@
 if [ "$CONFIG_IPX" != "n" ]; then
    source net/ipx/Config.in
 fi
-tristate 'Appletalk DDP' CONFIG_ATALK
+tristate 'Appletalk protocol support' CONFIG_ATALK
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'DECnet Support (EXPERIMENTAL)' CONFIG_DECNET
    if [ "$CONFIG_DECNET" != "n" ]; then
diff -u --recursive --new-file v2.3.49/linux/net/core/netfilter.c linux/net/core/netfilter.c
--- v2.3.49/linux/net/core/netfilter.c	Thu Mar  2 14:36:23 2000
+++ linux/net/core/netfilter.c	Sat Mar  4 20:03:50 2000
@@ -479,6 +479,7 @@
 				     info->indev, info->outdev, &elem,
 				     info->okfn);
 	}
+	br_read_unlock_bh(BR_NETPROTO_LOCK);
 
 	switch (verdict) {
 	case NF_ACCEPT:
diff -u --recursive --new-file v2.3.49/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.3.49/linux/net/core/skbuff.c	Sun Feb 20 21:12:40 2000
+++ linux/net/core/skbuff.c	Tue Mar  7 11:10:03 2000
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.68 2000/02/18 16:47:18 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.69 2000/03/06 03:47:58 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -204,6 +204,7 @@
 	skb->rx_dev = NULL;
 #ifdef CONFIG_NETFILTER
 	skb->nfmark = skb->nfreason = skb->nfcache = 0;
+	skb->nfct = NULL;
 #ifdef CONFIG_NETFILTER_DEBUG
 	skb->nf_debug = 0;
 #endif
@@ -246,6 +247,9 @@
 		}
 		skb->destructor(skb);
 	}
+#ifdef CONFIG_NETFILTER
+	nf_conntrack_put(skb->nfct);
+#endif
 #ifdef CONFIG_NET		
 	if(skb->rx_dev)
 		dev_put(skb->rx_dev);
@@ -282,6 +286,9 @@
 	n->is_clone = 1;
 	atomic_set(&n->users, 1);
 	n->destructor = NULL;
+#ifdef CONFIG_NETFILTER
+	nf_conntrack_get(skb->nfct);
+#endif
 	return n;
 }
 
@@ -314,6 +321,8 @@
 	new->nfmark=old->nfmark;
 	new->nfreason=old->nfreason;
 	new->nfcache=old->nfcache;
+	new->nfct=old->nfct;
+	nf_conntrack_get(new->nfct);
 #ifdef CONFIG_NETFILTER_DEBUG
 	new->nf_debug=old->nf_debug;
 #endif
diff -u --recursive --new-file v2.3.49/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.3.49/linux/net/ipv4/ip_output.c	Thu Feb 10 17:11:24 2000
+++ linux/net/ipv4/ip_output.c	Tue Mar  7 11:10:03 2000
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.80 2000/02/09 11:16:41 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.81 2000/03/06 03:48:01 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -889,6 +889,12 @@
 			iph->frag_off |= htons(IP_MF);
 		ptr += len;
 		offset += len;
+
+#ifdef CONFIG_NETFILTER
+		/* Connection association is same as pre-frag packet */
+		skb2->nfct = skb->nfct;
+		nf_conntrack_get(skb2->nfct);
+#endif
 
 		/*
 		 *	Put this fragment into the sending queue.
diff -u --recursive --new-file v2.3.49/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.49/linux/net/netsyms.c	Thu Mar  2 14:36:23 2000
+++ linux/net/netsyms.c	Fri Mar  3 12:54:44 2000
@@ -586,6 +586,8 @@
 EXPORT_SYMBOL(nf_unregister_queue_handler);
 EXPORT_SYMBOL(nf_hook_slow);
 EXPORT_SYMBOL(nf_hooks);
+EXPORT_SYMBOL(nf_setsockopt);
+EXPORT_SYMBOL(nf_getsockopt);
 #endif
 
 EXPORT_SYMBOL(register_gifconf);
